[英]Rails application behind proxy, with SSL, renders paths as “http://”
首先,這聽起來更像是一個錯誤,然后是其他任何東西。
我的rails應用程序由Unicorn提供服務。 然后,使用Nginx作為反向代理,我使用SSL將應用程序提供給外部世界。
到目前為止這么好,沒問題。 我正在使用相對路徑(Restful path helpers),所以生成它應該沒有問題(對於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"}
有沒有人遇到類似的東西? 任何想法都將被感激地接受......
我遇到了類似的問題。 默認情況下,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;
}
}
到目前為止,我已經設法通過在簡單的http下為Nginx添加重寫規則來獲得解決方法:
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
因此,無需更改我的代碼中的任何其他內容,我有一個工作相對重定向。
我認為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
這是一個快速復制粘貼工作。 如果您想要與redirect_to
具有相同的簽名,則需要更多努力
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.