2010-10-28 76 views
37

我知道有很多问题可以回答这个问题。我熟悉.htaccessnginx.conf方法,但我不能在heroku上访问这样的传统配置方法。如何使用Rails 3/Rack不使用www进行重定向?

Simone Carletti给出了这个答案,利用Rails 2.x金属,但我使用Rails 3,这是不兼容的。 Redirect non-www requests to www urls in Rails

请注意:

我不希望在我的ApplicationController简单before_filter。我想完成类似于Simone的重写。我相信这是最起码的web服务器或者中间件的工作,所以我想把这些东西留给实际的应用代码。

目标

redirect    to     status 
---------------------------------------------------- 
www.foo.com    foo.com    301 
www.foo.com/whatever foo.com/whatever 301 

只有主机配套/^www\./应该重定向。所有其他请求应该被忽略。

+0

非常感谢:) – Robin 2011-11-14 14:53:32

+0

我不明白需要每种方法。我的中间件没有它,它们像魅力一样工作。 – radiospiel 2013-06-01 12:46:47

+0

啊,现在我看到:自我在重定向的情况下作为响应主体返回,并且主体必须respond_to? :每。这可能不是规范的方式。我建议只是返回一个空字符串或[]作为响应正文。 – radiospiel 2013-06-01 12:59:22

回答

50

轨道4,5去除WWW。从任何URL,同时维持路径可以简单地通过以下方式实现:

# config/routes.rb 

constraints subdomain: 'www' do 
    get ':any', to: redirect(subdomain: nil, path: '/%{any}'), any: /.*/ 
end 

相比之下,加入万维网。到任何网址的开始尚未有它可以实现:

# config/routes.rb 

constraints subdomain: false do 
    get ':any', to: redirect(subdomain: 'www', path: '/%{any}'), any: /.*/ 
end 
+0

标记此答案为Rails 4用户接受。如果您使用rails'<= 3',请参阅此主题中的其他答案。 – 2014-01-31 01:49:09

+0

这真是太棒了! – alexzg 2015-02-15 21:52:45

+2

我不确定它是否是我正在做的事情,但是当使用'constraints subdomain:false'时,它实际上由于某种原因会执行两个重定向,最终会在'www.www.localhost:3000'中结束。在浏览器中,我可以看到它重定向了'localhost:3000' =>'www.localhost:3000' =>'www.www.localhost:3000' – 2015-09-10 17:17:43

7

在这个中间件看看,它应该做的正是你想要的东西:

http://github.com/iSabanin/www_ditcher

让我知道这是否为你工作。

+0

伊利亚,我将此视为已被接受,但我想出了一个稍微更优雅/强大的解决方案。根据[Rack Spec](http://rack.rubyforge.org/doc/SPEC.html),“Body本身不应该是String的一个实例,因为这将在Ruby 1.9中打破。”所以,我在这里做了调整。另外,我正在使用Rack :: Request对象来处理URL并使代码更清晰。 – 2010-10-29 08:59:13

13

如果您使用Rails 3,还有更好的方法。只要利用路由迷人的优势。

Foo::Application.routes.draw do 
    constraints(:host => /^example.com/) do 
    root :to => redirect("http://www.example.com") 
    match '/*path', :to => redirect {|params| "http://www.example.com/#{params[:path]}"} 
    end 
end 
+0

当www被指定时,我想在没有** www的情况下重定向**。你能适应你的答案吗?如果它有效,我会将其标记为已接受。 :) – 2010-11-01 05:51:37

+1

是否有可能你可以使它不可知域?例如''#{params [:protocol]}://#{params [:host]} /#{params [:path]}''? – 2010-11-01 05:53:02

6

在Rails 3

#config/routes.rb 
Example::Application.routes.draw do 
    constraints(:host => "www.example.net") do 
    match "(*x)" => redirect { |params, request| 
     URI.parse(request.url).tap { |x| x.host = "example.net" }.to_s 
    } 
    end 
    # .... 
    # .. more routes .. 
    # .... 
end 
+0

链接已损坏。 – iamnotmaynard 2016-10-31 20:08:22

+0

@iamnotmaynard我的答案中有相关的代码。 – 2016-11-02 16:27:44

12

我真的很喜欢使用Rails的路由器这样的事情。以前的答案很好,但我想要一些通用的东西,我可以使用任何以“www”开头的网址。

我认为这是一个很好的解决方案:

constraints(:host => /^www\./) do 
    match "(*x)" => redirect { |params, request| 
    URI.parse(request.url).tap {|url| url.host.sub!('www.', '') }.to_s 
    } 
end 
7

公爵的解决方案的一个行版本。只需添加到routes.rb中的顶部

match '(*any)' => redirect { |p, req| req.url.sub('www.', '') }, :constraints => { :host => /^www\./ } 
+0

谢谢!你能不能让另一个版本包含从onedomain.com到onedomain.net的重定向?如果两个域共享相同的名称,是否可以像req.url.sub('www。','')。sub('net','com')? – 2013-03-05 18:55:10

3

如果你想从顶级域名(TLD)到WWW子域名重定向,使用此代码:

constraints :subdomain => '' do 
    match '(*any)' => redirect { |p, req| req.url.sub('//', '//www.') } 
end 

注:此代码使用sub而不是gsub,因为sub会替换第一次出现的双斜杠,其中gsub将替换所有双斜杠。

+0

答案与此问题相反,但非常有用 - 谢谢! – Troy 2012-07-23 23:22:16

2

上述方法没有错,但也有一些gem提供Rack中间件来做到这一点。

我喜欢他们保持这种行为与应用程序本身分开的方式,但它不是一个特别强烈的论点。在使用Sinatra时,我也使用中间件来完成这项工作,所以更愿意使用我可以在Rails和/或Sinatra构建的应用程序上使用的技术(我经常运行内嵌在Rails中的Nesta)。

无论如何,它们是:

第一个是简单的(和一个我一直在使用),而第二提供了一些更多的功能(我还没有需要,但感激)。

3

对于导轨4,上述解决方案必须附加动词构造,例如, via: [:get, :post]。杜克大学的溶液变成:

constraints(:host => /^www\./) do 
    match "(*x)" => redirect { |params, request| 
     URI.parse(request.url).tap {|url| url.host.sub!('www.', '') }.to_s 
    }, via: [:get, :post] 
    end 
相关问题