使用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
相关产品推荐
相关产品推荐

