nginx配置遇到的问题
问题一:转发后缀是否带斜杠的问题
接收测试服务
from flask import Flask, request, jsonify
from gevent import pywsgi
app = Flask(__name__)
app.debug = True
app.config['JSON_AS_ASCII'] = False
@app.before_request
def request_before():
return success(request.path)
def success(data = None):
return response(0, "success",data)
def response(code, msg, data=''):
return jsonify({'code': code, 'msg': msg, 'data': data})
if __name__ == "__main__":
print("开始启动web服务器...")
server = pywsgi.WSGIServer(('0.0.0.0', 9999), app)
server.serve_forever()
这段代码直接监听9999端口,然后直接将请求的url返回,格式为:
{ code:0, msg:"success", data:"path" }
nginx 测试配置
server {
listen 999;
server_name localhost;
# location 匹配带'/'后缀 proxy_pass url带 '/' 后缀
location /prod-api/{
proxy_set_header Host $http_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_pass http://localhost:9999/;
}
# location 匹配不带'/'后缀 proxy_pass url带 '/' 后缀
location /dev-api {
proxy_set_header Host $http_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_pass http://localhost:9999/;
}
# location 匹配带'/'后缀 proxy_pass url不带 '/' 后缀
location /test-api/{
proxy_set_header Host $http_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_pass http://localhost:9999;
}
# location 匹配不带'/'后缀 proxy_pass url不带 '/' 后缀
location /api {
proxy_set_header Host $http_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_pass http://localhost:9999;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
实测结果
[root@localhost ~]# curl http://localhost:999/prod-api/api
{
"code": 0,
"data": "/api",
"msg": "success"
}
[root@localhost ~]# curl http://localhost:999/dev-api/api
{
"code": 0,
"data": "/api",
"msg": "success"
}
[root@localhost ~]# curl http://localhost:999/test-api/api
{
"code": 0,
"data": "/test-api/api",
"msg": "success"
}
[root@localhost ~]# curl http://localhost:999/api/api
{
"code": 0,
"data": "/api/api",
"msg": "success"
}
[root@localhost ~]#
结论
使用nginx做代理转发时是,是否
匹配前缀
是否会添加到proxy_pass
url后面取决于proxy_pass
的url后面是否带/
符号。
-
补充结论
当
proxy_pass
url 后面携带了/
的时候,nginx
会将location
后面的字符串添加到proxy_pass
的url后面。现在有两个情景:
-
配置一
location /api/ { proxy_pass http://x.xx/; }
如果请求
/api/getUserInfo
,实际转发的请求是http://x.xx/getUserInfo
-
配置二
location /api { proxy_pass http://x.xx/; }
如果请求
/api/getUserInfo
,实际转发的请求是http://x.xx//getUserInfo
从上面的结果可以看出
nginx
直接将location
匹配前缀后面的字符串直接拼接到了转发路径后面,不会主动给替换//
的情况,目前我知道的是有些web服务会主动给你替换下,但是spring security
不会去处理,会认为这是一个不标准的url,可能会有拦截的情况。
-
问题二:同端口使用不同目录的问题
背景:我们通常使用
nginx
部署web项目的时候,同一个项目可能有多个静态网站,而这多个静态网站需要使用同一个端口例如,我的某个web项目有三个服务
api服务
、门户网站
、管理系统前端
,而我想实现利用nginx
的location
匹配前缀不同前缀然后使用8080
端口访问,匹配需求如下:
匹配前缀 服务 服务类型 /api
转发到 8888
端口接口 /admin
访问 /a/b/c
目录静态网页 /
访问 /d/e/f
目录静态网页
想当然使用root
和 proxy_pass
我对
nginx
不是非常的熟悉,但是我知道可以使用root
来指定静态网页的目录,如果这样的话,我只需要使用location
配置块中设置不同root
即可,所以有了如下配置:
server {
listen 8080;
server_name _;
location /api {
proxy_set_header Host $http_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_pass http://127.0.0.1:8888/;
}
location /admin {
root /a/b/c/;
index index.html;
}
location / {
root /d/e/f/;
index index.html;
}
}
实测
-
访问
:8080/api
能正常转发到:8888
服务 -
访问
:8080/admin
报502,查看日志发现访问的是/a/b/c/admin/index.html
,而不是/a/b/c/index.html
-
访问
:8080/
正常访问/d/e/f/index.html
结论
本因为是和
proxy_pass
中的是否以/
结尾有关,后来发现修改后测试发现不是, 查阅资料发现需要更改location
需要使用到alias
使用alias
server {
listen 8080;
server_name _;
location /api {
proxy_set_header Host $http_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_pass http://127.0.0.1:8888/;
}
location ~ ^/admin(.*)$ {
alias /a/b/c/$1;
index index.html;
}
location / {
root /d/e/f/;
index index.html;
}
}
测试通过!
alias
可以通过使用正则提取的方式来改变实际访问的路径。
网友评论