获取HTTP请求,如通过有线传输(Django)

获取HTTP请求,如通过有线传输(Django),django,httprequest,Django,Httprequest,如果您有一个django请求对象,是否可以像通过有线传输一样通过测试环获取http请求 当然,如果使用https,纯文本不会加密 我想存储bytestring,以便稍后对其进行分析 充其量我想访问真正的bytestring。从request.META、request.GET和friends创建一个bytestring可能与原来的不同 更新:似乎不可能获得原始字节。然后问题是:如何构造一个大致与原始内容类似的bytestring?基本答案是否定的,Django没有访问原始请求的权限,事实上它甚至没

如果您有一个django请求对象,是否可以像通过有线传输一样通过测试环获取http请求

当然,如果使用https,纯文本不会加密

我想存储bytestring,以便稍后对其进行分析

充其量我想访问真正的bytestring。从request.META、request.GET和friends创建一个bytestring可能与原来的不同


更新:似乎不可能获得原始字节。然后问题是:如何构造一个大致与原始内容类似的bytestring?

基本答案是否定的,Django没有访问原始请求的权限,事实上它甚至没有解析原始HTTP请求的代码

这是因为Django与许多其他Python web框架一样,HTTP请求/响应处理在其核心是一个WSGI应用程序

前端/代理服务器(如Apache或nginx)和应用服务器(如uWSGI或gunicorn)的工作是处理请求(如转换和剥离头文件),并将其转换为可由Django处理的对象

作为一个实验,您实际上可以自己包装Django的WSGI应用程序,并查看Django在收到请求时使用了什么

编辑项目的wsgi.py并添加一些非常基本的wsgi中间件:

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project.settings')

class MyMiddleware:
    def __init__(self, app):
        self._app = app

    def __call__(self, environ, start_response):
        import pdb; pdb.set_trace()
        return self._app(environ, start_response)

# Wrap Django's WSGI application
application = MyMiddleware(get_wsgi_application())
现在,如果您启动devserver./manage.py运行服务器并向Django应用程序发送请求。您将进入调试器

这里唯一感兴趣的是environ dict。看看它,你会发现它与Django的request.META中的内容几乎相同。环境宣言的内容详见

知道了这一点,你能得到的最好的东西就是将环境中的项目拼凑到一个类似HTTP请求的东西上

但是为什么呢?如果您有一个environdict,那么您就有了复制Django请求所需的所有信息。实际上不需要将此转换回HTTP请求

事实上,正如您现在所知,调用Django的WSGI应用程序根本不需要HTTP请求。您所需要的只是一个带有所需键和可调用项的environ dict,以便Django能够转发响应

因此,要分析请求,甚至能够重播它们,您只需要能够重新创建一个有效的环境

在Django中,最简单的方法是将request.META和request.body序列化为JSON dict


如果您确实需要类似HTTP请求的内容,并且无法升级到Web服务器来记录此信息,则您只需将request.META和request.body中的可用信息拼凑在一起,需要注意的是,这不是原始HTTP请求的真实表示。

正如其他人指出的,这是不可能的,因为Django不与原始请求交互

您可以尝试像这样重新构造请求

def reconstruct_request(request):
    headers = ''
    for header, value in request.META.items():
        if not header.startswith('HTTP'):
            continue
        header = '-'.join([h.capitalize() for h in header[5:].lower().split('_')])
        headers += '{}: {}\n'.format(header, value)

    return (
        '{method} HTTP/1.1\n'
        'Content-Length: {content_length}\n'
        'Content-Type: {content_type}\n'
        '{headers}\n\n'
        '{body}'
    ).format(
        method=request.method,
        content_length=request.META['CONTENT_LENGTH'],
        content_type=request.META['CONTENT_TYPE'],
        headers=headers,
        body=request.body,
)
注意,这不是一个完整的示例,只是概念证明


不,您不能,因为是wsgi处理程序(例如uwsgi、gunicorn)解析原始请求并将其传递给Django。Django从未看到原始请求。@solarissmoke感谢您的评论。我根据我遇到的这个项目更新了这个问题,这个项目存储了请求和响应。但我没有研究实际的格式: