22

我发现这篇很棒的博客文章介绍了如何将Rack::Proxy其用作单独的代理应用程序。这篇文章解释了他如何使用Rack::Proxy代理请求到http://localhost:3000port 上的应用程序3001和请求到porthttp://localhost:3000/api上的应用程序3002。我想做同样的事情,但我不想创建单独的代理应用程序。相反,我希望我的主要 Rails 应用程序将请求代理/blog到另一个应用程序。

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

4

5 回答 5

32

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 或负载均衡器做正确的事情)。

于 2012-11-24T06:25:55.767 回答
14

这是对 steve 的解决方案的轻微改动,它使用了更少的内部理解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
于 2013-08-21T19:09:00.330 回答
3

弄清楚了。

库/代理.rb

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

    def rewrite_env(env)
        # do magic in here
    end
end

配置/应用程序.rb

config.middleware.use "Proxy"
于 2012-06-16T12:51:40.300 回答
1

当您希望http://localhost:3000/api/users/1(例如)在不使用代理服务器程序的情况下转到 routes.rb 中定义的 api 命名空间时,下面是更简单的代理 api 代码。

在生产中,它类似于http://api.sample.com/users/1

库/代理.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

配置/应用程序.rb

config.middleware.use "Proxy"

配置/路由.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
于 2016-11-20T11:17:42.213 回答
0

我发现 gem rails-reverse-proxy使用起来更加简单和明显(对于反应应用程序):

添加一个简单的代理控制器:

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]
于 2020-04-10T18:54:25.813 回答