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
Antwort
es herausgefunden.
lib/proxy.rbrequire '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"
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).
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. –
"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? –
@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
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
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
wäre schön zu sehen gewesen, was genau die „Magie“ war, dass Sie sprechen über – steve
Sie können Proxy.rb setzen in app/Middleware in Rails 4 –