5

因此,由于我的托管服务提供商(Heroku)的限制,目前我正在从裸域手动引导。一切正常。问题是,如果用户访问 mydomain.com/route,将发出重定向回 www.mydomain.com 而没有 /route。我将如何重新附加路线,但仍重定向到 www。?

class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :ensure_domain
APP_DOMAIN = 'www.domain.com'
def index
end
def ensure_domain
    if Rails.env.production?
        if request.env['HTTP_HOST'] != APP_DOMAIN
            redirect_to "http://#{APP_DOMAIN}", :status => 301
        end
    end
end
end

编辑

我从我的 ApplicationController 中删除了上面的代码,并选择使用hurikhan77 建议的折射 gem ,这解决了我的问题。

这是我使用的 refraction_rules.rb。

Refraction.configure do |req|
  if req.host == "domain.com"
    req.permanent! :host => "www.domain.com"
  end
end
4

3 回答 3

5

我建议为此使用折射宝石:http ://rubygems.org/gems/refraction

于 2012-11-24T00:42:01.387 回答
2

理想情况下,您会在 Web 服务器配置中设置类似的规则。请求会变得更快,因为它们甚至不会到达 rails 堆栈。也不需要向您的应用程序添加任何代码。

但是,如果您在某些受限环境中运行,例如 heroku,我建议您添加机架中间件。(仅供参考,不能保证此特定代码是否没有错误)

class Redirector
  SUBDOMAIN = 'www'

  def initialize(app)
    @app = app
  end

  def call(env)
    @env = env
    if redirect?
      redirect
    else
      @app.call(env)
    end
  end

private

  def redirect?
    # do some regex to figure out if you want to redirect
  end

  def redirect
    headers = {
      "location" => redirect_url
    }
    [302, headers, ["You are being redirected..."]] # 302 for temp, 301 for permanent
  end

  def redirect_url
    scheme = @env["rack.url_scheme"]

    if @env['SERVER_PORT'] == '80'
      port = ''
    else
      port = ":#{@env['SERVER_PORT']}"
    end

    path = @env["PATH_INFO"]

    query_string = ""
    if !@env["QUERY_STRING"].empty?
      query_string = "?" + @env["QUERY_STRING"]
    end

    host = "://#{SUBDOMAIN}." + domain # this is where we add the subdomain
    "#{scheme}#{host}#{path}#{query_string}"
  end

  def domain
    # extract domain from request or get it from an environment variable etc.
  end
end

你也可以单独测试整个事情

describe Redirector do
      include Rack::Test::Methods

      def default_app
        lambda { |env|
          headers = {'Content-Type' => "text/html"}
          headers['Set-Cookie'] = "id=1; path=/\ntoken=abc; path=/; secure; HttpOnly"
          [200, headers, ["default body"]]
        }
      end

      def app()
        @app ||= Rack::Lint.new(Redirector.new(default_app))
      end

      it "redirects unsupported subdomains" do
        get "http://example.com/zomg?a=1"
        last_response.status.should eq 301
        last_response.header['location'].should eq "http://www.example.com/zomg?a=1"
      end
     # and so on
end

然后您只能将其添加到生产环境(或任何首选环境)

# production.rb
# ...
config.middleware.insert_after 'ActionDispatch::Static', 'Redirector'

如果你想在开发中测试它,将同一行添加到 development.rb 并在你的 hosts 文件(通常是 /etc/hosts)中添加一条记录,将 yoursubdomain.localhost 视为 127.0.0.1

于 2012-11-24T13:10:39.280 回答
0

不确定这是否是最佳解决方案,但您可以正则表达式request.referrer并在 .com 之后提取任何内容并将其附加到APP_DOMAIN

或者我想你可以在第一个之前取出所有东西。request.env['HTTP_HOST']添加替换为假设http://www.您不打算使用子域。

于 2012-11-23T23:37:07.600 回答