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

如何实现SAP工时系统的multipart/mixed批量请求?

解决SAP OData Batch请求语法错误问题

问题诊断

你的请求代码存在两个明确语法错误,再加上手动构造batch请求的固有风险,导致服务器返回语法错误:

  • Header拼接错误:x-csrf-token: <some-token>==Content-Type: application/json 缺少换行分隔,两个HTTP头被合并,服务器无法解析。
  • JSON格式损坏:"ApproverPernr":"<some-number" 末尾缺少闭合双引号,破坏了JSON结构。
  • 手动拼接字符串易出错:SAP OData对batch请求的格式要求严格,直接写字符串很容易在换行、边界符、长度校验等细节上出错。

解决方案

1. 快速修复现有代码

先修正两个明显错误,同时补上batch请求必需的Content-Type头:

r = session.post(
    "<some-url>",
    params={"sap-client": "100"},
    headers={
        "Content-Type": "multipart/mixed; boundary=batch_9003-5d2c-29c4"
    },
    data='\r\n--batch_9003-5d2c-29c4\r\nContent-Type: multipart/mixed; boundary=changeset_34fb-a3ca-3327\r\n\r\n--changeset_34fb-a3ca-3327\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\nPOST TimeEventSet?sap-client=100 HTTP/1.1\r\nsap-contextid-accept: header\r\nAccept: application/json\r\nAccept-Language: de\r\nDataServiceVersion: 2.0\r\nMaxDataServiceVersion: 2.0\r\nx-csrf-token: <some-token>==\r\nContent-Type: application/json\r\nContent-Length: 152\r\n\r\n{"EmployeeID":"<some-number>","EventDate":"2024-04-19T00:00:00","EventTime":"PT17H10M6S","TimeType":"<some-code>","TimezoneOffset":"<some-offset>","ApproverPernr":"<some-number>"}\r\n--changeset_34fb-a3ca-3327--\r\n\r\n--batch_9003-5d2c-29c4--\r\n'
)

修正点:

  • 在x-csrf-token值后添加\r\n分隔Header
  • 给ApproverPernr的值补上闭合双引号
  • 新增batch请求的Content-Type头,指定对应boundary

2. 更可靠的实现:用工具构建multipart请求

手动拼字符串容错率低,推荐用requests-toolbelt的MultipartEncoder自动处理格式细节:

先安装依赖:

pip install requests-toolbelt

编写代码:

from requests_toolbelt.multipart.encoder import MultipartEncoder
import requests

session = requests.Session()

# 后续替换为动态获取的CSRF token
csrf_token = "<some-token>=="

# 构造内部POST请求内容
changeset_body = (
    f"POST TimeEventSet?sap-client=100 HTTP/1.1\r\n"
    f"sap-contextid-accept: header\r\n"
    f"Accept: application/json\r\n"
    f"Accept-Language: de\r\n"
    f"DataServiceVersion: 2.0\r\n"
    f"MaxDataServiceVersion: 2.0\r\n"
    f"x-csrf-token: {csrf_token}\r\n"
    f"Content-Type: application/json\r\n\r\n"
    '{"EmployeeID":"<some-number>","EventDate":"2024-04-19T00:00:00","EventTime":"PT15H15M29S","TimeType":"<some-code>","TimezoneOffset":"<some-offset>","ApproverPernr":"<some-number>"}'
)

# 生成随机边界符(符合OData规范)
batch_boundary = f"batch_{''.join(random.choices('abcdef0123456789', k=16))}"
changeset_boundary = f"changeset_{''.join(random.choices('abcdef0123456789', k=16))}"

# 构建changeset层级的multipart
changeset_encoder = MultipartEncoder(
    fields={'': (None, changeset_body, 'application/http')},
    boundary=changeset_boundary
)

# 构建外层batch层级的multipart
batch_encoder = MultipartEncoder(
    fields={'': (None, changeset_encoder.read(), f'multipart/mixed; boundary={changeset_boundary}')},
    boundary=batch_boundary
)

# 发送请求
response = session.post(
    "<some-url>",
    params={"sap-client": "100"},
    headers={
        "Content-Type": batch_encoder.content_type,
        # 带上登录后的Cookie等必要头信息
    },
    data=batch_encoder
)

# 查看结果
print(response.status_code)
print(response.text)

3. 额外注意事项

  • 每次请求的batch/changeset边界符要随机生成,避免固定值触发服务器安全校验
  • 确保session保留登录状态的Cookie,否则请求会被拦截
  • 动态获取CSRF token时,先发送一个HEAD/GET请求到目标服务,从响应头的x-csrf-token字段提取值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:21:26