首先,这听起来更像是一个错误,而不是其他任何东西。
我的rails应用程序由Unicorn提供服务。然后,使用Nginx作为反向代理,我使用SSL将应用程序提供给外部世界。
到目前为止这么好,没问题。我使用相对路径(Restful path helpers),所以生成它(https://www.example.com)应该没有问题:
new_entry_path => https://www.example.com/entries/new
大多数情况下都可以正常使用。
但是在控制器中我会尝试重定向到" show"动作(使用资源),让我们说成功更新后(假设输入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 :(得分:6)
我有类似的问题。默认情况下,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;
}
}
答案 1 :(得分:1)
到目前为止,我已经设法通过在简单的http:
下向Nginx添加重写规则来获得解决方法rewrite ^/(.*)$ https://www.example.com/$1? permanent;
将所有普通http
请求重定向到https
服务器。
<强>更新强>
显然,因为我希望应用程序不关心前端Web服务器如何服务它,所以由同一个Web服务器来“清除重定向的混乱”应用程序本身无法处理,除非它是专门配置的(不希望如此)。所以,我会坚持这个答案(解决方法而不是......)
<强>更新强>
按照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
因此,无需更改我的代码中的任何其他内容,我就有一个工作相对重定向。
答案 2 :(得分:1)
我认为force_ssl
正是您所寻找的。 p>
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
这是一个快速复制的粘贴作业。如果您想要与redirect_to