websocket服务器在用http://localhost:8888/bbbb/websocket请求时总是报错,经过分析发现是nginx的问题,于是有了这篇文章。
location /bbbb/websocket{
rewrite ^/bbbb/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketbbbb/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
1.1.1.1 - - [07/Nov/2019:15:58:42 +0800] "POST /bbbb/websocket HTTP/2.0" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
POST / HTTP/1.1
Host: abc.ddd.cn
X-Real-IP: 1.1.1.1
REMOTE-HOST: 1.1.1.1
X-Forwarded-For: 1.1.1.1
Connection: Upgrade
Content-Length: 10
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36
cache-control: no-cache
origin: chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop
x-requested-with: XMLHttpRequest
accept-language: zh-CN,zh;q=0.9,en;q=0.8
postman-token: 17daff12-3bcc-4c1c-4c9f-2f5aebaa3cd5
content-type: application/x-www-form-urlencoded
accept: */*
sec-fetch-site: cross-site
sec-fetch-mode: cors
accept-encoding: gzip, deflate, br
6666666666HTTP/1.1 404 Not Found
content-length: 13
404 Not Found
结果为:
before request method is:POST req uri is:/-[]
before request method is:POST req uri is://-[]
before request method is:POST req uri is://aaaa-[]
原因是 rewrite 规则没生效,因为把rewrite那一行去掉,重启nginx之后,各种请求呈现的结果无殊。同时我们需要注意的是proxy_pass的规则,当rewrite不生效时:
也就是与location匹配上之后多出的那一段都会加到proxy_pass后面。
关于proxy_pass更多的说明,参考下这篇文章:https://blog.csdn.net/ainuser/article/details/80260144 说明,这种情况下不会与rewrite规则匹配上,所以路径直接与proxy_pass匹配。
location /bbbb/websocket/{
rewrite ^/bbbb/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketbbbb/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
1.1.1.1 - - [07/Nov/2019:14:43:27 +0800] "POST /bbbb/websocket/ HTTP/2.0" 302 154 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
1.1.1.1 - - [07/Nov/2019:14:43:27 +0800] "GET /404.html HTTP/2.0" 200 754 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
1.1.1.1 - - [07/Nov/2019:14:44:19 +0800] "POST /bbbb/websocket HTTP/2.0" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
1.1.1.1 - - [07/Nov/2019:14:44:23 +0800] "GET /bbbb/websocket/ HTTP/2.0" 302 154 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
1.1.1.1 - - [07/Nov/2019:14:44:23 +0800] "GET /404.html HTTP/2.0" 200 754 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
两种情况下均为 post 请求,可以看出,在第一种情况下请求被转换成了 GET,从而导致后台 websocket 服务报错。第二种情况正常工作。
原因在于location的路径为/bbbb/websocket/,而实际发送请求的路径为/bbbb/websocket,当请求匹配上时nginx会自动在后面添加一个目录/,然后进行重定向,关于这个问题,可以参考:https://www.cnblogs.com/zeoblog/p/6046144.html。也就是说这种情况下的匹配会有两步,先添加一层目录进行301重定向,然后再次匹配时路径是正确的,但是请求方式由post改成了get,从而导致后台服务报错。
注意,这个301不是rewrite引起的,break操作下的rewrite是不会重定向的。添加目录的操作是在location路径的最后一层匹配时发生的。对于get和post请求如果路径不正确时都会出现重定向的情况,只是post方式重定向后会变成get。 说明,这种情况下都会与rewrite规则匹配上,所以会先进行rewrite之后再将rewrite的结果加在proxy_pass上。
配置修改为:
location /bbbb/{
rewrite ^/bbbb/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketbbbb/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
这种情况下,请求路径为/bbbb/websocket时会完全匹配location,不会再往路径后面添加/,不会先进行301重定向。
说明,这种情况下rewrite和proxy_pass都能正常工作,而且不会出现nginx自动添加一层目录的问题。