查看错误日志发现:所有的请求都返回了405错误
raise HTTPError(405)\ntornado.web.HTTPErr
or: HTTP 405: Method Not Allowed
查看代码,我确实调用的是post方法,但查看日志发现codo-admin收到的是一个get方法:
data = {
"username": user_detail.get('name'),
"nickname": user_detail.get('name'),
"tel": user_detail.get('mobile'),
"ding_id": user_detail.get("userid"),
"email": user_detail.get('email'),
"role": "developer"
}
res = requests.post(url, json=data)
服务端收到的请求:
"GET /api/accounts/user_inner/ HTTP/1.1" 405 337 "-" "python-requests/2.23.0"
POST请求被转为GET请求,推测是由于http请求被Nginx转为https导致的,因此先将原http请求链接改成https,问题解决。
为什么POST会变GET
如果客户端发出POST请求后,收到服务端的301/302状态码,那么不能自动的向新的URI发送重复请求,必须跟用户确认是否该重发,因为第二次POST时,环境可能已经发生变化(嗯,POST方法不是幂等的),POST操作会不符合用户预期。但是,很多浏览器(useragent我描述为浏览器以方便介绍)在这种情况下都会把POST请求变为GET请求。
由于浏览器的这个特性,在http的标准rfc2616中,规定了当收到服务端的301/302状态码时,不能向URI发送重复请求,需要用户确认,并且,增加了一个303状态码,当收到303状态码时,浏览器获取HTTP报文头部的Location字段信息,并直接发起一个GET请求,而303是1.1标准才加入的,大多数浏览器的实现都把301/302状态码作为303的方式来处理,因此,发出的POST请求变成了GET。实际上,在http标准中是禁止将301,302改get的,但实际实现都是这么做的
Nginx干了点啥
Nginx在配置http请求强制转为https时,通过rewrite来实习重定向,因此会给浏览器返回一个302/301状态码, Nginx配置如下:
server {
listen 80;
server_name shandian.xiaoduoai.com;
return 301 https://$server_name$request_uri;
}
301状态码代表永久重定向到新点uri
由于在codo的入口处就已经是https请求,转发就不是在codo上配置的,需要查看其上一层。
解决: 307状态码
POST方法的重定向在未询问用户的情况下就变成GET,这种不符合文档规范的问题依然存在。实践在前而文档在后,HTTP1.1把这种POST变GET的行为纳入了RFC文档:HTTP1.1新加入303和307状态码。
文档中规定303状态码的响应,也就是上边提到的现在浏览器对302状态码的处理:POST重定向为GET。
HTTP1.1文档中307状态码则相当于HTTP1.0文档中的302状态码,当客户端的POST请求收到服务端307状态码响应时,需要跟用户询问是否应该在新URI上发起POST方法,也就是说,307是不会把POST转为GET的。
HTTP1.1中,301/302理论上是要被放弃掉的,它被细化为303和307,但为了兼容,它目前还在业界中大量使用。
在Nginx配置中,使用307状态码进行转发,POST请求就不会再被改为GET请求。
只需要修改Nginx配置:
server {
listen 80;
server_name shandian.xiaoduoai.com;
return 307 https://$server_name$request_uri;
}
将301改为307即可解决。