关于如何将Rack::Proxy
用作单独的代理应用,我发现这很棒blog post。本文介绍了如何使用Rack::Proxy
将http://localhost:3000
的请求代理到端口3001
上的应用,并向http://localhost:3000/api
请求端口3002
上的应用。我想做同样的事情,但我不想创建一个单独的代理应用程序。相反,我希望我的主Rails应用程序将对/blog
的请求代理到另一个应用程序。
答案 0 :(得分:29)
FWIW,我也刚刚解决了这个问题。有些人可能会发现完整的代码很有帮助,因为我需要的比你发布的更多:
# 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
此外:
# config/application.rb
# ...snip ...
module MyApplication
class Application < Rails::Application
# Custom Rack middlewares
config.middleware.use "ProxyToOther" if ["development", "test"].include? Rails.env
#...snip....
这假设你想要代理某些请求的应用程序正在端口3001上运行。我敢说你正在打的应用程序可以在任何端口上运行。这也假设您只想在开发和测试环境中进行代理,因为您将在生产中获得“真正的”解决方案。暂存(例如,nginx或负载均衡器做正确的事情)。
答案 1 :(得分:14)
对于史蒂夫的解决方案略有改动,对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
答案 2 :(得分:3)
想出来。
的 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
的配置/ application.rb中强>
config.middleware.use "Proxy"
答案 3 :(得分:1)
如果您希望http://localhost:3000/api/users/1(例如)在不使用代理服务器程序的情况下转到routes.rb中定义的api命名空间,则代理api的代码更简单。
在制作时,它会像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
<强>配置/ application.rb中强>
config.middleware.use "Proxy"
<强>配置/ 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
答案 4 :(得分:0)
我发现 rails-reverse-proxy 宝石更简单易用(对于React应用):
添加一个简单的代理控制器:
class ProxyController < ApplicationController
include ReverseProxy::Controller
def index
reverse_proxy "http://localhost:3000" do |config|
# We got a 404!
config.on_missing do |code, response|
redirect_to root_url and return
end
end
end
end
并添加一条路线:
match 'static/*path' => 'proxy#index', via: [:get, :post, :put, :patch, :delete]