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

使用Python Requests向XenForo论坛上传文件遇400错误求助

XenForo论坛文件上传400错误解决方案

核心问题分析

XenForo采用Flow.js分片上传协议,所有flow*前缀的参数是服务器强制校验项,不能省略;同时请求必须携带有效的_xfToken令牌,否则会触发400/500错误。

修复步骤

1. 补充所有必填Flow参数

必须传递的参数列表:

  • flowChunkNumber:当前分片序号(单文件上传填1)
  • flowChunkSize:分片大小(XenForo默认值为4294967296,即4GB)
  • flowCurrentChunkSize:当前分片实际字节数(单文件时与flowTotalSize一致)
  • flowTotalSize:文件总字节数
  • flowIdentifier:格式为文件大小-无空格文件名(需与浏览器生成规则一致)
  • flowFilename:原始文件名
  • flowRelativePath:原始文件路径(与文件名一致即可)
  • flowTotalChunks:总分片数(单文件填1)
  • _xfToken:从发帖页面提取的CSRF令牌
  • _xfResponseType:固定值json
  • _xfWithData:固定值1

2. 修正文件上传字段

XenForo接收文件的字段名是upload,而非自定义的filename,必须严格对应。

3. 移除手动指定的Content-Type

requests库会自动处理multipart/form-data的boundary,手动指定会导致边界不匹配,引发400错误。

修正后的完整代码

import requests
import os

cookies = {
    'xf_csrf': 'xx',
    'userinit': 'xx',
    'xf_user': 'xx',
    'xf_session': 'xx',
    'xf_sam_ad_views': 'xx',
}

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.71 Safari/537.36',
    'Accept': '*/*',
    'Origin': 'https://www.xx.xx',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Dest': 'empty',
    'Referer': 'https://www.redacted.xxxx/index.php?forums/uploading-your-files-here.132/post-thread',
    'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
}

s = requests.Session()
s.cookies.update(cookies)

# 获取发帖页面、nodeid、hash和_xfToken
post_thread_url = 'https://www.redacted.xxxx/index.php?forums/uploading-your-files-here.132/post-thread'
response = s.get(post_thread_url, headers=headers, verify=False)
print(f"页面请求状态码: {response.status_code}")

nodeid = response.text.split("node_id]=", 1)[1][:3]
upload_hash = response.text.split("hash=", 1)[1][:32]
xf_token = response.text.split('name="_xfToken" value="')[1].split('"')[0]

print(f"nodeid: {nodeid}, hash: {upload_hash}, xf_token: {xf_token}")

# 准备文件信息
file_path = "Name of the file.txt"
file_size = os.path.getsize(file_path)
file_name = os.path.basename(file_path)
flow_identifier = f"{file_size}-{file_name.replace(' ', '')}"

# 构建表单数据
form_data = {
    '_xfToken': xf_token,
    '_xfResponseType': 'json',
    '_xfWithData': '1',
    'flowChunkNumber': '1',
    'flowChunkSize': '4294967296',
    'flowCurrentChunkSize': str(file_size),
    'flowTotalSize': str(file_size),
    'flowIdentifier': flow_identifier,
    'flowFilename': file_name,
    'flowRelativePath': file_name,
    'flowTotalChunks': '1',
}

# 构建文件对象
files = {
    'upload': (file_name, open(file_path, 'rb'), 'application/octet-stream')
}

# 发送上传请求
upload_url = f'https://www.redacted.xxxx/index.php?attachments/upload&type=post&context[node_id]={nodeid}&hash={upload_hash}'
upload_response = s.post(upload_url, data=form_data, files=files, headers=headers, verify=False)

print(f"上传请求状态码: {upload_response.status_code}")
print(f"上传响应内容: {upload_response.text}")

额外注意事项

  • 若文件超过4GB,需实现分片拆分逻辑,按序号依次上传
  • _xfToken需每次请求发帖页面重新提取,避免过期失效
  • 对比Burp抓包参数与代码参数,确保空格、大小写、特殊字符完全一致
  • 若仍报错,检查服务器返回的响应内容,通常会包含具体的校验失败原因

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:20:27