WSGI服务正确处理path与path_info
source link: http://ladder1984.github.io/post/wsgi%E6%9C%8D%E5%8A%A1%E6%AD%A3%E7%A1%AE%E5%A4%84%E7%90%86path%E4%B8%8Epath_info/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
WSGI服务正确处理path与path_info
需要把原app1.yy.com,app2.yy.com.. 的域名合并成xx.yy.com/app1 , xx.yy.com/app2的部署方式,在测试合并域名部署时,发现前端发来的请求,个别页面报错,观察到的情况是
此时Nginx配置如下:
server {
listen 80;
server_name xxx.yy.com;
location /app1/{
proxy_pass http://192.168.6.183:19910/;
}
}
- Nginx接受请求http://xxx.yy.com/app1/api/get_order 后通过proxy_pass转发给http://192.168.6.183:19910/
- wsgi服务,即Django,接受到http://xxx.yy.com/api/get_order请求
- 按照Django url匹配原则,即项目代码定义的url(r’api/get_order/$‘, …)
3.1 会首先认为api/get_order匹配失败,
3.2 根据Django默认设置APPEND_SLASH=True,会发起重定向补全“/”,根据request.host和request.path_info,得到重定向url:http://xxx.yy.com/api/get_order/ - NGINX无法匹配 /api/get_order/,返回404
根本原因是,Django服务无法感知到path: /app1的存在,所以重定向生成的URL有误。对此,解决方案有:
- 在Django设置APPEND_SLASH=False,关闭自动补全。但所有客户端必须正确请求携带/的URL,但排查老代码,以及规避以后代码请求出错风险较大
- 通过Django中间件的方式在处理url匹配前自动加上/,但此方案只能处理APPEND_SLASH场景,不确定Django是否还有其他类似重定向,也使得后端服务丧失发起重定向能力,风险较大
- 彻底解决path问题,使得后端服务正确感知到完整path是/app1/api/get_order,并能正确处理
经查询,对于多个服务部署到同一域名的多个path下,Nginx、wsgi、Django是有支持的。需要使用SCRIPT_NAME特性。
根据wsgi定义,详见 https://www.python.org/dev/peps/pep-0333/#id19:
SCRIPT_NAME:URL请求中路径开始的部分,对应应用程序对象 PATH_INFO:URL请求路径剩余部分,指定请求目标在应用程序内部的虚拟位置
即完整的path是SCRIPT_NAME + PATH_INFO,以上述场景,SCRIPT_NAME是/app1,PATH_INFO是/api/get_order。
而Django能够正确处理SCRIPT_NAME
和PATH_INFO
,url匹配时是使用path_info,而append_slash
这样需要完整path的场景,get_full_path
函数能够正确识别SCRIPT_NAME,所以只要正确把SCRIPT_NAME + PATH_INFO传给Django就行了。http://xxx.yy.com/app1/api/get_order
请求,Django能解析到request.path: /app1/api/get_order
,request.path_info: /api/get_order
。
具体方案如下:
Nginx配置文件:
server { listen 80; server_name xx.yy.com; location /app1/{ uwsgi_pass 192.168.6.81:9999; uwsgi_param SCRIPT_NAME /app1; include uwsgi_params; } }
uWSGI的init配置文件:
... route-run = fixpathinfo: ...
注意uWSGI需要2.0.11及以上版本,详见:https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Changelog-2.0.11.html#fixpathinfo
https://note.qidong.name/2017/11/uwsgi-script-name/
https://uwsgi-docs-zh.readthedocs.io/zh_CN/latest/Changelog-2.0.11.html
https://www.python.org/dev/peps/pep-0333/#id19
文章作者 ladder1984
上次更新 2019-07-25
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK