代理后面的Rails应用程序,使用SSL,将path呈现为“http://”

首先,这听起来更像是一个错误,然后是其他任何东西。

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

到目前为止这么好,没有问题。 我正在使用相对path(Restfulpath助手),所以应该没有问题产生( https://www.example.com ):

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

这在大多数情况下工作正常。

但是,当我在一个控制器尝试redirect到“显示”操作(使用资源)时,出现了这个问题,假设成功更新(假设条目为100):

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

要么

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

他们都会产生一个redirect到:

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

代替

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

据我注意到,这只发生在show动作,只有在控制器redirect。

我通过做一些可怕而令人厌恶的事情绕过了这个:

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

有没有人遇到类似的东西? 任何想法将被感激地接受…

我有一个类似的问题。 默认情况下,Rails将使用*_url助手的当前协议。

我们使用nginx作为Web服务器和独角兽作为应用程序服务器。 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; } } 

我认为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具有相同的签名,请花点功夫

到目前为止,我已经设法通过添加一个重写规则到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([az][az\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 

因此,不必改变我的代码中的其他任何东西,我有一个工作的相对重定向。