我编写了中间件来捕获请求并在管理页面上查看它们。它成功查看原始文本请求正文,但在图像渲染上失败。
admin.py
class RequestLogEntryAdmin(admin.ModelAdmin):
fieldsets = (
('Request', {
'fields': ('request_headers', 'request_size', 'request_body_'),
})
)
def request_body_(self, obj):
if b'Content-Type: image/png' in base64.b64decode(obj.request_body):
return obj.image_handler(bytes(obj.request_body))
return bytes(obj.request_body)
模型.py
class RequestLogEntry(models.Model):
# ...
request_body = models.BinaryField(null=True)
# ...
def image_handler(self, binaryfield):
return mark_safe(f'<img src="data:image/png;base64,{binaryfield}" width="150" height="150" />')
保存 request.body 之前正在进行 base64 编码
中间件.py
# ...
log_entry.request_body = base64.b64encode(request.body)
# ...
Base64 解码后的 request.body 如下所示: 我的猜测是一些额外的数据与图像字节混合在一起(例如“Content-Disposition”和“Content-Type”标头),但我不确定如何从请求正文中将其删除。
当您像这样编码
HttpRequest.body
时:
base64.b64encode(request.body)
您实际上是将原始 HTTP 请求正文(这是一个
bytestring
)编码为 Base64 [wikipedia.org] 编码字符串。
HTTP 是基于文本的协议。正文和标题表示为字符序列。 Django 通过将原始主体保留在
HttpRequest.body
中来保留 HTTP 的这一功能,供任何想要在这个低级别工作的人使用。
但是由于请求包含文件,你应该这样处理:
if request.FILES:
file = request.FILES.get("image")
if file:
log_entry.request_body = file.read() #[1]
现在
image_handler()
必须稍微改变一下,因为 binaryfield
是二进制数据的原始位,而不是 Base64 字符串。
def image_handler(self, binaryfield):
return mark_safe(f"<img src='data:image/png;base64,{base64.b64encode(binaryfield)}' width='150' height='150' />")
[1] 在
read()
上调用 UploadedFile
时,您实际上是将 UploadedFile
中的全部数据读取到内存中。使用此方法时要小心:如果上传的文件很大,它可能会压垮您的系统。