Django restframework是怎么确定响应内容的格式的?关于HTTP协议的又一点认识。
再用restframework编写接口的时候,会使用 APIView 和 rest_framework.response.Response,然后今天发现一个问题:
我在用浏览器发送请求的时候,响应的是text/html, 返回的是一个页面
以前调试的时候只知道这个页面真方便,真好看,另外我们的前端也没有反映过设么问题。
直到今天测试Java的http请求,发现我获取的不是json!!!而是一个HTML文本,这真的是个大问题,试问如果有一天我用Java访问Django编写的服务端,正好服务端用了Response类,那么我拿到的是json???
但是我用postman发起请求得到的就是json,诡异!
当时就认为可能是请求头的问题,但是没往Accept上注意。
真正的原因就是请求头里面的Accept字段,浏览器发起请求,该字段是:
里面没有 application/json。
优先解决办法: 在请求头添加 Accept:application/json
问题到这里就解决了,后面是框架代码分析
在Django restframework框架里,会有两个渲染类,
这两个类是用来对所有Response相关类做渲染的,那么框架是怎么执行渲染的呢?
APIView的dispatch方法,在得到响应后,会执行 finalize_response方法
在红线处,会去执行一个操作,概括起来就是从请求头获取接受类型,以此来决定使用哪个渲染类:
进入select_render方法:
rest_framework.negotiation.DefaultContentNegotiation.select_renderer
关键在两处标红处,第一处,分离出所有Accept类型,renderers就是上面的两个渲染类的列表,代码先后遍历两个渲染类,然后在第二个红标处进行匹配。
如果请求头携带的Accept与任一个匹配,那么返回该渲染类。
具体的,感兴趣的可以到这一块去看
到这里,逻辑就走完了,最后回到这里:
响应Response的渲染类被确定,框架最后使用该类执行渲染。
框架调用该方法,输出渲染结果。
这一坨代码真的让我一通好找!!!
问题的主要原因是HTTP协议不熟悉,但是我之所以这么一通找,主要是想搞清楚,Restframework是怎么判定输出类型的
所以,如果想让接口就输出json格式,一个办法是让调用者在请求头添加 Accept:*/* 或者 application/json;
或者用下面的方式: