如何实现CherryPy请求体的二次读取?
解决CherryPy中请求体二次读取的问题
我之前也碰到过这个头疼的情况!CherryPy的RequestBody对象确实不像标准Python文件对象那样支持seek方法,因为它是直接从HTTP请求流里一次性读取数据,读完之后流就到末尾了,自然第二次读不到内容。不过有几个简单实用的办法能解决这个问题:
方法1:一次性读取后缓存内容
这是最直接高效的方案——第一次读取请求体后,把内容存在变量里,后续需要的时候直接复用这个变量就行,不用再去操作request.body:
import cherrypy class MyHandler: @cherrypy.expose def index(self): body_length = int(cherrypy.request.headers['Content-Length']) # 第一次读取并缓存内容 cached_body = cherrypy.request.body.read(body_length) print(len(cached_body)) # 输出338 # 后续直接使用缓存的内容,无需再次读取request.body data2 = cached_body print(len(data2)) # 同样输出338 return "处理完成"
方法2:将RequestBody包装成可重复读取的流对象
如果你确实需要用类文件对象的方式多次读取,可以把读取到的原始内容放进BytesIO(Python3)或者StringIO(Python2)里,这样就能支持seek和重复读取操作了:
import cherrypy from io import BytesIO # Python3用这个,Python2请用StringIO.StringIO class MyHandler: @cherrypy.expose def index(self): body_length = int(cherrypy.request.headers['Content-Length']) raw_data = cherrypy.request.body.read(body_length) # 把原始内容包装成可seek的流对象 body_stream = BytesIO(raw_data) # 第一次读取 data1 = body_stream.read(body_length) print(len(data1)) # 338 # 将流指针重置到开头 body_stream.seek(0) # 第二次读取 data2 = body_stream.read(body_length) print(len(data2)) # 338 return "处理完成"
方法3:让CherryPy自动缓存请求体
CherryPy内置了请求体缓存机制,你可以通过调用request.body.process()方法,或者启用cherrypy.tools.request_body工具,让框架自动把请求体内容缓存到内存中,之后的request.body会变成支持seek的类文件对象,就能重复读取了:
方式A:使用工具装饰器
import cherrypy class MyHandler: @cherrypy.expose @cherrypy.tools.request_body() # 启用工具自动缓存请求体 def index(self): body_length = int(cherrypy.request.headers['Content-Length']) data1 = cherrypy.request.body.read(body_length) print(len(data1)) # 338 # 重置指针后二次读取 cherrypy.request.body.seek(0) data2 = cherrypy.request.body.read(body_length) print(len(data2)) # 338 return "处理完成"
方式B:手动调用process方法
import cherrypy class MyHandler: @cherrypy.expose def index(self): # 手动触发请求体缓存 cherrypy.request.body.process() body_length = int(cherrypy.request.headers['Content-Length']) data1 = cherrypy.request.body.read(body_length) print(len(data1)) # 338 cherrypy.request.body.seek(0) data2 = cherrypy.request.body.read(body_length) print(len(data2)) # 338 return "处理完成"
一般来说,如果只是需要重复使用请求体内容,方法1是最省心的;如果需要模拟文件对象的操作逻辑,方法2或3会更适配你的场景。
内容的提问来源于stack exchange,提问作者colio303
相关产品推荐
相关产品推荐

