2014-09-26 104 views
2

首先,这看起来更像是一个错误,然后是其他任何东西。Rails应用程序在代理之后,使用SSL,将路径呈现为“http://”

我的导轨应用程序由Unicorn提供。然后,使用Nginx作为反向代理,我使用SSL将应用程序提供给外部世界。

到目前为止好,没问题。我使用相对路径(宁静路径佣工),所以应该没有问题,产生这样(为https://www.example.com):

new_entry_path => https://www.example.com/entries/new 

这在大多数情况下的罚款。

当控制器我尝试重定向到一个“秀”操作(使用资源),让成功更新后说,这个问题却出现(假设输入ID为100):

redirect_to @entry, flash: {success: "Entry has been updated"} 

redirect_to entry_path(@entry), flash: {success: "Entry has been updated"} 

他们都产生一个重定向到:

http://www.example.com/entries/100 # missing 's' in https... 

在的

/entries/100 # implying https://www.example.com/entries/100 

代替据我已经注意到,这仅与show行动,只有在控制器重定向发生。

redirect_to entry_url(@entry).sub(/^http\:/,"https:"), flash: {success: "Entry has been updated"} 

有没有人遇到类似的事情:

我做什么可怕的,恶心的绕过这个?任何想法将欣然接受......

+0

有你尝试设置默认主机? http://stackoverflow.com/questions/2660172/how-do-i-set-default-host-for-url-helpers-in-rails – max 2014-09-26 21:48:12

+0

我见过,但我试图让object_path helpers工作,而不是object_url帮手......这会帮助我吗? – 2014-09-26 21:50:09

+0

我相信如此,因为'redirect_to'使用''url_for' [引擎盖下](https://github.com/rails/rails/blob/3e006d5076a393c827fba69bf72bc36b7abf921b/actionpack/lib/action_controller/metal/redirecting.rb#L65) – max 2014-09-26 21:58:57

回答

1

到目前为止,我已经成功通过添加重写规则的Nginx获得一个解决办法,在普通HTTP:

rewrite ^/(.*)$ https://www.example.com/$1? permanent; 

所有普通http请求重定向到https服务器。

更新:

很显然,我希望应用程序不关心前面Web服务器是如何为它服务,它是由同一个web服务器来“清理残局”重定向应用程序通过本身不能处理,除非它被特别配置(不需要)。所以,我会坚持这个答案(解决方法,而...)

UPDATE
继papirtiger的回答,我看到了,我结束了缺少闪烁,这应该被添加到上位redirect_to作为参数。

但是我找到了一种让我的生活更容易的方法,只需重写一个不同的功能,即从redirect_to中调用。

def _compute_redirect_to_location(options) #:nodoc: 
    case options 
    # The scheme name consist of a letter followed by any combination of 
    # letters, digits, and the plus ("+"), period ("."), or hyphen ("-") 
    # characters; and is terminated by a colon (":"). 
    # See http://tools.ietf.org/html/rfc3986#section-3.1 
    # The protocol relative scheme starts with a double slash "//". 
    when /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i 
     options 
    ## WHEN STRING: THIS IS REMOVED TO AVOID ADDING PROTOCOL AND HOST ## 
    # when String 
    # request.protocol + request.host_with_port + options 
    when :back 
     request.headers["Referer"] or raise RedirectBackError 
    when Proc 
     _compute_redirect_to_location options.call 
    else 
     url_for(options) 
    end.delete("\0\r\n") 
end 

因此,无需改变任何东西在我的代码,我有一个工作相对重定向。

1

我认为force_ssl是你在找什么。

class AccountsController < ApplicationController 
    force_ssl if: :ssl_configured? 

    def ssl_configured? 
    !Rails.env.development? 
    end 
end 

编辑,如果你真的想这样做重定向到相对路径你总是可以创建自己的帮手:

module ActionController 
    module RelativeRedirectingHelper 
    extend ActiveSupport::Concern 

    include AbstractController::Logger 
    include ActionController::RackDelegation 
    include ActionController::UrlFor 

    def redirect_to_relative(path, response_status = 302) #:doc: 
     raise ActionControllerError.new("Cannot redirect to nil!") unless options 
     raise ActionControllerError.new("Cannot redirect to a parameter hash!") if options.is_a?(ActionController::Parameters) 
     raise AbstractController::DoubleRenderError if response_body 

     self.status  = response_status 
     self.location  = path 
     self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.h(location)}\">redirected</a>.</body></html>" 
    end 
    end 
end 

这是一个quick'n'dirty复制粘贴工作。如果你想拥有和redirect_to

+0

这是另一种解决方法......但我并不是说应用程序要”关心“它是否是ssl,反向代理做ssl-thingy ...我在找什么,是'something_path'作为'something_path'而不是'something_url' ... – 2014-09-27 14:32:59

+1

'redirect_to'会尝试使它成为绝对的因为根据当前版本的HTTP/1.1标准RFC 2616,Location标头的值必须是绝对URI。 – max 2014-09-27 16:47:51

+1

您可以随时制作自己的重定向帮手,看看https://github.com/rails/rails/blob/3e006d5076a393c827fba69bf72bc36b7abf921b/actionpack/lib/action_controller/metal/redirecting.rb#L65 – max 2014-09-27 16:51:46

4

相似的问题,请花费一点努力。默认情况下,Rails将使用*_url助手的当前协议。

我们使用nginx作为web服务器,unicorn作为应用服务器。 Nginx接受请求,解包SSL部分,然后将其传递给独角兽。因此,独角兽总是收到http请求。如果我们现在想让Rails知道原始协议,我们可以添加X-Forwarded-Proto头。

示例配置:

upstream app { 
    server unix:/var/run/myserver/unicorn.sock fail_timeout=0; 
} 
server { 
    listen  443 ssl; 
    server_name myserver; 

    ssl_certificate "/etc/pki/nginx/myserver.crt"; 
    ssl_certificate_key "/etc/pki/nginx/private/myserver.key"; 

    root /myserver/public; 

    try_files $uri/index.html $uri @app; 
    sendfile on; 

    location @app { 
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
     proxy_set_header X-Forwarded-Proto https; # <--- will be used 
     proxy_set_header Host $http_host; 
     proxy_redirect off; 
     proxy_pass http://app; 
    } 
} 
相关问题