从https重定向到http?

Posted

技术标签:

【中文标题】从https重定向到http?【英文标题】:Redirecting from https to http? 【发布时间】:2019-09-10 00:01:46 【问题描述】:

这里有一个奇怪的问题。我使用 FullCalendar 向服务器上的端点发起 ajax 请求。端点是:

https://my_website/events/?start=2019-03-31&end=2019-05-12&_=1555698739056

请注意,它是明确的 https。但是,当我发起请求时(即 Fullcalendar 发起请求时),我得到 301 和重定向到非 https 端点:

http://my_website/events?start=2019-03-31&end=2019-05-12&_=1555698739056

失败,因为页面是通过 https 加载的。

端点工作正常 - 当我将它加载到浏览器中时,我得到了预期的 json 输出(通过 https)。此页面上发生的其他 ajax 请求可以正常工作,并且我在此站点的其他地方(到另一个端点)成功地使用 Fullcalendar 完成了完全相同的事情。只是这一种情况出现了意外。

可能值得注意的是,它位于 nginx 反向代理/负载均衡器后面的 docker 容器中;站点配置非常简单:

upstream docker 
    server localhost:8701;
    server localhost:8702;
  

server 
    server_name my_website;
    location / 
      proxy_pass http://docker;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
      # proxy_set_header                HTTP_Country-Code $geoip_country_code;
        proxy_pass_request_headers      on;
    

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/my_website/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/my_website/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot



server 
    if ($host = my_website) 
        return 301 https://$host$request_uri;
     # managed by Certbot

    listen 80;
    server_name my_website;
    return 404; # managed by Certbot


请求的nginx日志是这样的:

134.124.11.91 - - [19/Apr/2019:13:49:49 -0500] "GET /events/?start=2019-04-28&end=2019-06-09&_=1555699678658 HTTP/1.1" 301 0 "https://my_website" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/73.0.3683.103 Safari/537.36"

有没有人看到我遗漏的东西会导致这个奇怪的 301 重定向到非 https 端点?

【问题讨论】:

您的 nginx 配置中没有任何内容可能导致此重定向。可能是您的端点发起重定向,因为请求是通过 HTTP 代理的。为了确认,我建议将 $upstream_status 变量添加到 log_format。如果它等于 301,那么我是对的。它可能可以通过在 proxy_pass 中使用 https 或更改端点代码来解决。 【参考方案1】:

问题

这似乎是因为您没有使用规范 URL,而您的后端通过这些 301 重定向强制执行此类 URL,而它实际上并不知道规范地址方案。


解决方案

最好的解决方案是修复您的 前端 代码以始终使用规范 URL。例如,在您提供的示例中,您的 API 端点中是否存在尾部斜杠是不同的。

您可能应该配置您的 后端 以正确了解它正在通过 https 访问,例如,在所有其他的旁边添加类似以下内容nginx 中的 proto_set_header 指令终止 https 并将流量传递到后端:

proto_set_header    X-Forwarded-Proto   $scheme;

其他想法

另一种解决方案是配置http://nginx.org/r/proxy_redirect 以正确识别后端返回的本地Location 标头,并根据需要即时转换它们;但是,根据您的情况,前两个选项可能是更好的方法。

【讨论】:

谢谢,但是 1) 我看不出我的问题中斜杠和非斜杠之间有什么区别;哪个端点没有斜杠? 2) 显式设置 x-forwared-proto 标头没有帮助;和 3)我玩过 proxy_redirect 一点,但无济于事。关于如何使用它的任何具体建议? (1),你的问题有https://my_website/events/?,然后是http://my_website/events?——原始请求有一个斜杠,重定向没有。 (3),proxy_redirect 的第一个参数可能是http://my_website/,第二个,https://my_website/;当然,这取决于您最初的问题是否正确,因为第一部分必须与您的后端在其Location 回复中生成的内容完全匹配。【参考方案2】:

我不完全确定,因为你的截图有点矛盾,但这里是:

在您的检查器屏幕截图中,我们看到一个对 https 的请求(已被取消)和一个对 http 的请求(由于混合协议而被阻止)。提示在被取消的那个中,被取消意味着那里没有重定向,但浏览器认为它不再需要该请求。之前有几个问题有类似的问题,见here和here两个例子。

请求被取消的一个原因是,如果您用来更改 FullCalendar 日期的按钮/输入/链接不仅执行 ajax 请求,而且执行第二个 http 请求(因为包装表单、href、等等)。您还没有包含您的 FullCalendar 实现的 html 和 javascript,所以我不确定这一点,但请检查您是否没有围绕输入元素的表单,或者如果您编写了自己的事件处理程序,请执行以下操作。

function(e)
  e.preventdefault(); 

  .... // your date switching code here 

  return false;

如果您使用带有 onclick 属性的链接,请确保在末尾添加 ...(yourcode);return false;

重要提示:如果我的理论是正确的,这意味着您的日志中的行实际上与我们在检查器中看到的内容并不对应,实际上是从 HTTP 到 HTTPS 的重定向,不是相反。这很难看到,因为 nginx 默认不将请求协议包含在日志中。

【讨论】:

以上是关于从https重定向到http?的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP 从 HTTP 重定向到 HTTPS

将所有子域从 http 重定向到 https

Grails 重定向控制器从 https 切换到 http。为啥?

从 http 重定向到 https 时,从 url 中删除斜线

Tomcat 不会从 HTTP 重定向到 HTTPS

将某些页面从 HTTPS 重定向到 HTTP