Nginx proxy_set_header 解析和延升add_header指令 【转】

本文会先由一个问题引入,然后再进行多种情况进行分析。

一、问题和排查步骤

1.1 问题基本信息

​         我们应用程序从代码层面收到的 Header 中的 Host 的值是 upstream 的 名称。 我们程序是需要获取到实际的值。所以这里存在一个问题。

        我们先看看我们的 nginx 配置。

upstream open-hz8443{
server 10.60.6.184:8000 max_fails=1 fail_timeout=3s weight=10;
}

server{
        server_name 192.168.80.132;
        listen 80;
        proxy_set_header   Host             $host;
        proxy_set_header   X-Real-IP        $remote_addr;
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
        proxy_connect_timeout   3s;
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
        proxy_next_upstream error timeout invalid_header http_404 http_502 http_504 http_500;

        location / {
                proxy_pass http://open-hz8443;
        }
        location ^~ /wss/v1
        {
            proxy_pass  http://open-hz8443;
            proxy_set_header Connection "upgrade";
            proxy_set_header Upgrade $http_upgrade;
            tcp_nodelay on;
        }
}

        我们请求 http://192.168.80.132/wss/v1, 我们可以在后端(10.60.6.184:8000)获取到 Host 的值为 open-hz8443

        这个是我们做了一个 脚本,用于获取请求的所有的数据的。 脚本具体内容在文末。

Connection: upgrade
Host: open-hz8443    # 获取到的Host 是 open-hz8443
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 FS
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

10.210.20.43 - - [04/Jan/2021 15:54:46] "GET /wss/v1 HTTP/1.0" 200 -

1.2 问题解析

首先这里有知识点:

我们在 Server 配了 

proxy_set_header Host $host; 

, 我们在 location 是只配置了

proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;

     我们的 Host 最初我认为是会继承 Server 配置的 proxy_set_header Host $host; , 但是明显是没有继承的,而是直接拿的 upstream 的名称。说明没有继承,那么这里是有一个什么规则? 我们往下看。

  1. 查询 Nginx 官方文档。

    Module ngx_http_proxy_module

    Allows redefining or appending fields to the request header passed to the proxied server. 
    The value can contain text, variables, and their combinations.
    These directives are inherited from the previous configuration level if 
    and only if there are no proxy_set_header directives defined on the current level. 
    By default, only two fields are redefined:
    

             大概意思就是当我们没有设置 proxy_set_header 才会从上一层级继承,当我们设置了 proxy_set_header ,也就意味着我们不从上面 server 的 proxy_set_header Host $host; 进行继承。

    那为什么会显示 open-hz8443, 是因为有一个默认值

    proxy_set_header Host       $proxy_host;
    

    这个 proxy_host

    • 当我们设置了 upstream 的话,也就是上面的例子$proxy_host 就是 upstream的名称值.
    • 当我们直接使用的 proxy_pass http://10.60.6.184:8000 的话,那么 $proxy_host 表示的就是 10.60.6.184:8000

1.3、解决办法

在 location ^~ /wss/v1 下面增加配置 proxy_set_header Host $host;

        location ^~ /wss/v1
        {
            proxy_pass  http://open-hz8443;
            proxy_set_header   Host     $host;
            proxy_set_header Connection "upgrade";
            proxy_set_header Upgrade $http_upgrade;
            tcp_nodelay on;
        }

二、扩展-各种情况对比

proxy_set_header  默认两项

proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

proxy_set_header 其他项

proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
Server 设置 proxy_set_header 其他项Server 设置 proxy_set_header 默认两项location 设置 proxy_set_header 默认两项location 设置 proxy_set_header 其他项默认值生效默认值不生效
11111 继承location
11011(不继承Server)
11101 继承location
11001 继承server
10101 继承location
10001 默认
100111 默认
10111 继承location
01001 继承server
01011 默认
01101 继承location
01111 继承location
00011 默认
00101 继承location
00111 继承location
00001 默认

总结

  1. location 设置了 proxy_set_header 就不继承,但继承默认值,默认值优先级低于 location设置。
  2. location 未设置了proxy_set_header ,就往上继承,直到默认值。

只要调用了 proxy_set_header,并没有设置 host 和 connection ,默认重写host、connection两个头。

三、扩展 ->脚本

proxy_set_header $host $proxy_host $http_host 各个变量含义

记录一次 Nginx 配置 proxy_pass 后 返回404问题

python 获取请求所有数据信息脚本

#!/usr/bin/env python

import SimpleHTTPServer
import SocketServer

PORT = 8000

class GetHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
    def do_GET(self):
        print(self.headers)
        self.send_response(200, "")
    def do_POST(self):
        print(self.headers)
        content_length = self.headers.getheaders('content-length')
        length = int(content_length[0]) if content_length else 0
        print(self.rfile.read(length))
        self.send_response(200, "")

Handler = GetHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
httpd.serve_forever()

扩展:add_header指令

官方的介绍:

Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). The value can contain variables.

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

If the always parameter is specified (1.7.5), the header field will be added regardless of the response code.

意思也就是说话在响应状态码成功时,add_header 指令才生效,并且当前《作用域》下没有 add_header 指令时,会向上层继承。

转自:

一次 Nginx proxy_set_header 故障问题解析和延升 - 自由早晚乱余生 - 博客园

<think>好的,我现在需要解决用户提出的关于Nginx配置WebSocket升级头的问题。用户提到遇到了proxy_set_header的配置问题,可能涉及到WebSocket无法正确升级的情况。我需要先回忆一下Nginx配置WebSocket的相关知识,并结合提供的引用内容来组织回答。 首先,WebSocket协议需要HTTP/1.1的支持,而Nginx默认的代理设置可能使用的是HTTP/1.0,这会导致问题。根据引用[1][5],Nginx默认的proxy_http_version是1.0,而WebSocket需要1.1版本。所以第一步是设置proxy_http_version 1.1。 然后,关于UpgradeConnection头。引用[1]、[3]、[4]都提到必须设置这两个头。默认情况下,Nginx不会发UpgradeConnection头,所以需要用proxy_set_header手动设置。Upgrade头应该取客户端的$http_upgrade变量,而Connection头通常设为"upgrade"。不过引用[2]提到了一种更灵活的方式,使用map指令根据$http_upgrade是否存在来动态设置Connection头,这可能在某些情况下更可靠,比如当客户端请求中没有Upgrade头时,自动关闭连接,避免保持不必要的长连接。 接下来,用户可能需要具体的配置示例。根据引用中的例子,可以整理出一个标准的配置模板,包括设置http版本、UpgradeConnection头,同时可能包含map指令的部分。 还要注意检查其他可能的配置问题,比如proxy_pass是否正确指向后端服务,是否有其他冲突的配置覆盖了这些设置。此外,确保Nginx版本支持WebSocket代理,通常较新的版本没有问题,但旧版本可能需要更新。 用户可能遇到的问题可能包括配置遗漏、版本不匹配,或者没有正确重新加载Nginx配置。在回答时需要分步骤说明配置要点,并给出示例,同时提醒常见的注意事项,比如重新加载配置、检查日志等。 最后,生成相关问题时要围绕WebSocket配置、Nginx代理设置、常见错误排查等方面,帮助用户进一步了解可能遇到的类似问题。</think>### Nginx配置WebSocket升级头解决方案 WebSocket协议需要特殊的Nginx代理配置才能正常工作,核心配置点涉及**HTTP版本升级****请求头设置**。以下是分步解决方案: 1. **强制使用HTTP/1.1协议** - 修改默认的代理HTTP版本: ```nginx proxy_http_version 1.1; # 必须设置为1.1支持协议升级[^1][^5] ``` 2. **设置UpgradeConnection标头** - 显式传递客户端请求头: ```nginx proxy_set_header Upgrade $http_upgrade; # 继承客户端Upgrade头[^3] proxy_set_header Connection "upgrade"; # 固定值标识协议升级[^4] ``` - 更灵活的配置方案(推荐): ```nginx map $http_upgrade $connection_upgrade { default upgrade; '' close; } server { location /websocket/ { proxy_set_header Connection $connection_upgrade; # 动态设置Connection头[^2] } } ``` 3. **完整配置示例** ```nginx server { listen 80; server_name example.com; location /ws/ { proxy_pass http://backend_server; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # 或使用动态配置: proxy_set_header Connection $connection_upgrade; } } ``` **验证步骤**: 1. 执行 `nginx -t` 测试配置语法 2. 执行 `nginx -s reload` 重载配置 3. 通过浏览器开发者工具检查WebSocket连接的`HTTP 101 Switching Protocols`响应 4. 查看Nginx错误日志 `/var/log/nginx/error.log` 排查连接问题 **常见错误排查**: - 未设置`proxy_http_version 1.1`导致协议升级失败[^5] - Connection头值未正确设置为"upgrade"(注意大小写敏感)[^3] - 防火墙拦截WebSocket端口(默认ws使用80端口,wss使用443) - 后端服务未正确实现WebSocket协议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值