You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Django单元测试中如何为伪造HTTP请求添加请求体?

Django单元测试中伪造带XML请求体的POST请求

问题描述

在Python Django项目里,我们想通过单元测试给被测函数传入HTTP POST请求。原本用cURL命令会触发Web服务器端点的完整逻辑路径,但我们希望单元测试聚焦于接收request参数的特定函数。已经拿到伪造HTTP请求的Python代码,但不知道怎么像cURL的-d参数那样,把XML格式的请求体传入伪造的请求对象中。

相关技术细节

cURL命令

curl http://127.0.0.1:8000/api/transaction/ --insecure \
    --verbose \
    -d '<env:Envelope ... >
  <env:Header>
    ...
  </env:Header>
  <env:Body>
    ...
  </env:Body>
</env:Envelope>
'

现有伪造请求代码

from django.core.handlers.wsgi import WSGIRequest
from io import StringIO
from django.contrib.auth.models import AnonymousUser

def GetFakeRequest(path='/', user=None):
    """ Construct a fake request(WSGIRequest) object"""
    req = WSGIRequest({
        'REQUEST_METHOD': 'GET',
        'PATH_INFO': path,
        'wsgi.input': StringIO()})

    req.user = AnonymousUser() if user is None else user
    return req

解决方案

要伪造带XML请求体的POST请求,需要对现有函数做以下关键调整:

  • 修改请求方法为POST
  • 将XML内容转为字节流传入wsgi.input
  • 设置匹配XML类型的CONTENT_TYPE头和正确的CONTENT_LENGTH

修改后的完整代码:

from django.core.handlers.wsgi import WSGIRequest
from io import BytesIO  # WSGI要求wsgi.input为字节流,替换StringIO
from django.contrib.auth.models import AnonymousUser

def GetFakePostRequestWithXml(path='/', user=None, xml_body=''):
    """构造带XML请求体的伪造POST请求对象"""
    # 将XML字符串编码为字节流
    xml_bytes = xml_body.encode('utf-8')
    wsgi_input = BytesIO(xml_bytes)
    
    req = WSGIRequest({
        'REQUEST_METHOD': 'POST',
        'PATH_INFO': path,
        'wsgi.input': wsgi_input,
        'CONTENT_TYPE': 'text/xml; charset=utf-8',
        'CONTENT_LENGTH': str(len(xml_bytes)),
        # 可选:添加与cURL一致的请求头,比如Accept
        'HTTP_ACCEPT': '*/*',
    })

    req.user = AnonymousUser() if user is None else user
    return req

使用示例

# 定义XML请求体
xml_payload = '''<env:Envelope ... >
  <env:Header>
    ...
  </env:Header>
  <env:Body>
    ...
  </env:Body>
</env:Envelope>'''

# 生成伪造请求
fake_request = GetFakePostRequestWithXml(
    path='/api/transaction/',
    xml_body=xml_payload
)

# 传入被测函数执行测试
result = your_target_function(fake_request)

关键注意点

  • 必须用BytesIO:WSGI规范要求wsgi.input是字节流对象,不能用处理字符串的StringIO,否则Django无法正确解析请求体。
  • 不能省略CONTENT_LENGTH:Django的WSGIRequest会依赖这个值读取请求体内容,缺失会导致无法获取XML数据。
  • 匹配实际的CONTENT_TYPE:如果接口期望application/xml,需要对应修改这个头的值,和cURL请求保持一致。

内容的提问来源于stack exchange,提问作者James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:45:05