Twisted设置application/json响应头客户端收到text/html如何解决
Twisted Web响应Content-Type始终为text/html问题排查
问题现象
- 搭建的Twisted Web服务预期返回JSON格式数据,已尝试将响应
Content-Type设置为application/json,但客户端接收到的响应头中该字段始终为text/html - 服务端在调用
request.finish()前打印的响应头如下:
b'Server' = [b'TwistedWeb/22.4.0'] b'Date' = [b'Fri, 08 Jul 2022 18:35:59 GMT'] b'Content-Type' = [b'application/json']
- 客户端实际接收到的响应头如下:
b'Transfer-Encoding' = b'chunked' b'Server' = b'TwistedWeb/22.4.0' b'Date' = [b'Fri, 08 Jul 2022 18:35:59 GMT'] b'Content-Type' = b'text/html'
- 问题复现代码:
import json from twisted.web import server, resource from twisted.internet import reactor class Resource(resource.Resource): def render(self, request): def return_json(data): request.write(json.dumps(data, separators=(',', ':')).encode()) request.setHeader(b'content-type', b'application/json') request.finish() deferred = someFunctionReturningDeferred() deferred.addCallback(return_json) return server.NOT_DONE_YET site = server.Site(Resource()) reactor.listenTCP(PORT, site) reactor.run()
根本原因
request.finish()本身不会篡改已设置的响应头,问题出在响应头的设置时机错误:
- Twisted的Request对象在第一次调用
request.write()方法时,就会将当前内存中存储的所有响应头、状态行序列化后发送给客户端,响应头部分发送完成后才会开始传输响应体 - 上述代码中先执行了
request.write()发送JSON响应体,此时还未设置Content-Type,Twisted会自动使用默认值text/html填充该头字段,随响应头一起发送给客户端 - write操作完成后才调用
request.setHeader()修改Content-Type,仅会修改Request对象内存中存储的头字段值,无法修改已经发送到网络上的响应内容,因此服务端在finish前打印内存中的头字段显示为application/json,但客户端实际收到的是已经发送出去的默认头 - 响应头中的
Transfer-Encoding: chunked是Twisted在未提前设置Content-Length时自动启用的分块传输编码,和该问题无关
修复方法
调整响应头设置顺序,必须在第一次调用request.write()之前完成所有响应头的设置,修改后的回调函数逻辑如下:
def return_json(data): # 先设置所有响应头 request.setHeader(b'content-type', b'application/json') # 再发送响应体 request.write(json.dumps(data, separators=(',', ':')).encode()) request.finish()
调整后响应头会在第一次write时正确携带设置的application/json值,客户端即可收到符合预期的响应头。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

