2012-06-15 2 views
17

Ich fand diese große blog post auf wie Rack::Proxy als separate Proxy-Anwendung zu verwenden. In diesem Artikel wird erläutert, wie er Rack::Proxy verwendet, um Anfragen an http://localhost:3000 an eine App an Port 3001 und Anfragen an http://localhost:3000/api an eine App auf Port 3002 zu übertragen. Ich möchte das Gleiche tun, aber ich möchte keine separate Proxy-App erstellen. Stattdessen möchte ich, dass meine Rails-App Anfragen an /blog an eine andere App weiterleitet.Wie verwende ich Rack :: Proxy innerhalb von Rails Proxy-Anforderungen an einen bestimmten Pfad zu einer anderen App

Blog: http://livsey.org/blog/2012/02/23/using-rack-proxy-to-serve-multiple-rails-apps-from-the-same-domain-and-port/

Antwort

3

es herausgefunden.

lib/proxy.rb
require 'rack-proxy' 
class Proxy < Rack::Proxy 
    def initialize(app) 
     @app = app 
    end 

    def rewrite_env(env) 
     # do magic in here 
    end 
end 
config/application.rb
config.middleware.use "Proxy" 
+19

wäre schön zu sehen gewesen, was genau die „Magie“ war, dass Sie sprechen über – steve

+1

Sie können Proxy.rb setzen in app/Middleware in Rails 4 –

29

FWIW, habe ich auch nur dieses Problem in Angriff genommen. Einige können den vollständigen Code hilfreich, da ich mehr benötigt, als Sie auf dem Laufenden:

# lib/proxy_to_other.rb 
class ProxyToOther < Rack::Proxy 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    original_host = env["HTTP_HOST"] 
    rewrite_env(env) 
    if env["HTTP_HOST"] != original_host 
     perform_request(env) 
    else 
     # just regular 
     @app.call(env) 
    end 
    end 

    def rewrite_env(env) 
    request = Rack::Request.new(env) 
    if request.path =~ %r{^/prefix|^/other_prefix} 
     # do nothing 
    else 
     env["HTTP_HOST"] = "localhost:3000" 
    end 
    env 
    end 
end 

auch:

# config/application.rb 
# ...snip ... 
module MyApplication 
    class Application < Rails::Application 
    # Custom Rack middlewares 
    config.middleware.use "ProxyToOther" if ["development", "test"].include? Rails.env 
#...snip.... 

Dies setzt voraus, Ihre Anwendung, die Sie einige Anfragen an den Proxy wollen 3001. I läuft auf Port Ich wage zu behaupten, dass die App, die Sie treffen, auf jedem Port ausgeführt werden kann. Dies setzt auch voraus, dass Sie nur das Proxing in Entwicklungs- und Testumgebungen durchführen wollen, da Sie eine "echte" Lösung in der Produktion haben (zB nginx oder ein Loadbalancer, der das Richtige tut).

+2

Das ist großartig.Wenn Sie eine beliebige App im Internet als Proxy verwenden möchten, müssen Sie möglicherweise auch 'env ["SERVER_PORT"] = 80' setzen. –

+0

"Dies setzt auch voraus, dass Sie nur die Proxying in Entwicklungs- und Testumgebungen durchführen wollen, weil Sie' Ich habe eine "echte" Lösung in der Produktion und Inszenierung (zB nginx oder ein Loadbalancer, der das Richtige tut). " - Warum das? Soll ich Rack :: Proxy nicht in der Produktion verwenden? –

+2

@DavidLojudiceSobrinho könnten Sie sicherlich, aber es wäre besser, dass Proxying mit Nginx/Apache oder Loadbalancer. Sie verwenden in Ihrer App einen Thread, um eine synchrone HTTP-Anfrage an einen anderen Server zu senden. Es ist einfach kein kluger Umgang mit Ressourcen. – steve

14

Dies ist eine geringfügige Änderung Lösung Steves, die ein wenig weniger internes Verständnis von Rack::Proxy verwendet:

require 'rack/proxy' 

class MyProxy < Rack::Proxy 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    # call super if we want to proxy, otherwise just handle regularly via call 
    (proxy?(env) && super) || @app.call(env) 
    end 

    def proxy?(env) 
    # do not alter env here, but return true if you want to proxy for this request. 
    return true 
    end 

    def rewrite_env(env) 
    # change the env here 
    env["HTTP_HOST"] = "some.other.host" 
    env 
    end 
end 
1

Im Folgenden noch einfache Code-Proxy der eine api ist, wenn Sie wollen http://localhost:3000/api/users/1 (zum Beispiel) gehen api-Namespace, der in routes.rb definiert ist, ohne ein Proxy-Server-Programm zu verwenden.

Bei der Produktion wäre es so etwas wie http://api.sample.com/users/1.

lib/proxy.rb

require 'rack-proxy' 

class Proxy < Rack::Proxy 
    def perform_request(env) 
    request = Rack::Request.new(env) 
    if request.path =~ %r{^/api} 
     #do nothing 
    else 
     @app.call(env) 
    end 
    end 
end 

config/application.rb

config.middleware.use "Proxy" 

config/routes.rb

namespace :api, defaults: { format: :json }, 
     constraints: { subdomain: 'api' }, path: '/' do 
    scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do 
    resources :users, :only => [:show, :create, :update, :destroy] 
end 

lib/api_constraints.rb

class ApiConstraints 
    def initialize(options) 
    @version = options[:version] 
    @default = options[:default] 
    end 

    def matches?(req) 
    @default || req.headers['Accept'].include?("application/vnd.sample.v#{@version}") 
    end 
end 
Verwandte Themen