簡體   English   中英

代理后面的Rails應用程序,使用SSL,將路徑呈現為“http://”

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM