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;

 

 

 

或者用下面的方式:

 

posted @ 2021-04-16 20:03  华腾海神  阅读(72)  评论(0编辑  收藏  举报