ruby-on-rails-3.1 proxy rack reverse-proxy routes

ruby on rails 3.1 - ¿Cómo uso Rack:: Proxy en Rails para enviar solicitudes a una ruta específica a otra aplicación?



ruby-on-rails-3.1 reverse-proxy (4)

Encontré esta excelente publicación en el blog sobre cómo usar Rack::Proxy como una aplicación proxy separada. El artículo explica cómo usa Rack::Proxy para enviar solicitudes a http://localhost:3000 a una aplicación en el puerto 3001 y solicitudes a http://localhost:3000/api a una aplicación en el puerto 3002 . Quiero hacer lo mismo, pero no quiero crear una aplicación proxy separada. En su lugar, quiero que mi aplicación Rails principal envíe solicitudes de proxy a /blog para una aplicación diferente.

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


A continuación se muestra un código aún más sencillo para representar una api cuando desea que http://localhost:3000/api/users/1 (por ejemplo) vaya al espacio de nombres de la api definido en route.rb sin utilizar un programa de servidor proxy.

En producción sería algo así como 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 / route.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


Este es un ligero cambio en la solución de steve que usa un poco menos de comprensión interna de Rack::Proxy :

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


FWIW, también acabo de abordar este problema. Algunos pueden encontrar el código completo útil, ya que necesitaba más de lo que usted publicó:

# 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

También:

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

Esto supone que su aplicación a la que desea enviar proxy se está ejecutando en el puerto 3001. Me parece que la aplicación que está golpeando puede ejecutarse en cualquier puerto. Esto también supone que solo desea realizar el proxy en entornos de desarrollo y prueba, porque tendrá una solución "real" en producción y puesta en escena (por ejemplo, nginx o un equilibrador de carga que haga lo correcto).


Lo averigué.

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"