单纯使用Django为微信小程序提供后端接口,我负责后端接口、同学负责前端,我们测试了get请求是没有问题的,但是在发送post请求时,前端收到的返回值一直是500和403。
(PS:想直接看解决方法的可以点击下方的“解决方案”跳转过去)
目录
1.返回 500(服务器错误)
1.1前端代码
1.2后端接口
def get2(request):
if request.method == "POST":
id = request.POST.get('id')
return HttpResponse({"result": id+5})
从上面的前端代码可以看得到,url的最后是没有加 / 的,其得到的返回值是500,然后我在后端接口把if语句删除,直接返回,但是前端的返回值依然不变,还是500。
1.3尝试的办法
1.3.1修改前端 header
在网上搜到一些资料,说是将前端代码的header修改:
header = {
'content-type': 'application/x-www-form-urlencoded',
}
修改完以后仍然是错误的,返回值依然是500。
1.3.2修改后端获取参数的方式
看了很多资料以后,我感觉前端代码的写法没有问题,于是我认为是后端获取post请求的参数时出现了错误,我就尝试使用别的方式获取参数:
- 第一种
def get2(request):
req_data = self.request.body
req_data = json.loads(req_data)
id = req_data.get('id')
return HttpResponse({"result": id+5})
- 第二种
def get2(request):
id = request.data['id']
return HttpResponse({"result": id+5})
上述两种办法都不行,返回值依然是500,此时我感觉很奇怪,我就想看看这些请求发过来以后经历了什么。于是我将后端代码加了一句print语句,判断请求的类型:
def get2(request):
print(request.method)
id = request.POST.get('id')
return HttpResponse({"result": id+5})
输出结果让我大吃一惊,因为它输出的是“GET”,那么请求的返回值是500就很容易理解了,因为我一直是使用获取POST请求参数的格式,所以服务就发生了错误返回500。然后我去查询请求的记录,我发现每一个POST请求的返回值都是301(也就是永久性重定向:本网页被永久性转移到另一个URL)。于是我去搜索原因,解决以后就出现了下面的问题。
2.返回 403(禁止访问,服务器收到请求,但拒绝提供服务)
通过前面的分析,我感觉事情很奇怪,因为每个POST请求都被永久性重定向了,查询了一些资料后我才了解到:django在url定向的时候,如果末尾不是‘/’,会被系统重定向到带‘/’的url,即301,然后空的请求被重定向,就变成了get。
如此我兴奋地让前端的同学把url最后面加上了 / ,但是一测试,返回值变成了403。
2.1尝试的办法
2.1.1修改nginx相关配置
因为部署django项目时是使用的nginx+uwsgi,在网上看到有人说nginx可能导致post请求返回403,搜了一些资料,感觉解决方法都比较麻烦,因此没有采用。(大家可以自行搜索一下)
3.解决方案
在搜索POST请求总是返回403时,偶然看到一个资料,其中提到这是一个跨域请求问题
(Django 中表单所需的 CSRF模板标签可防止跨站点请求伪造。CSRF使客户端浏览器访问过的恶意站点可以向您自己的服务器发出请求。因此,django 提供的 csrf_token 使您的 django服务器和站点可以轻松地免受此类恶意攻击。如果您的表单不受 csrf_token 保护,django 将返回 403禁止页面。这是对您网站的一种保护形式,尤其是在未故意遗漏令牌时。)
但是在某些情况下,django 站点不想使用 csrf_token 保护其表单,故Django提供了一个装饰器**@csrf_exempt**,此装饰器将视图标记为不受中间件确保的保护。
所以做出如下修改:
#在程序中导入csrf_exempt
from django.views.decorators.csrf import csrf_exempt
#在想接受POST请求的函数前面加上 @csrf_exempt
@csrf_exempt
def get2(request):
print(request.method)
id = request.POST.get('id')
return HttpResponse({"result": id+5})
如此前端的请求就可以正常得到返回值了,返回状态为200。
4.总结
- 前端的url需要以 / 结尾
- 修改前端 ‘content-type’
header = {
'content-type': 'application/x-www-form-urlencoded',
}
- 后端接口函数前面加 @csrf_exempt
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def get2(request):
print(request.method)
id = request.POST.get('id')
return HttpResponse({"result": id+5})
如果有不正确的地方请大家指正,感谢大家。