使用Python Requests通过PUT上传文件至Discord API遇问题求助
Discord文件上传问题排查与修复
你的代码存在几个关键问题,导致上传的附件无效:
问题点分析
- PUT请求携带多余的Authorization头:Discord返回的
upload_url已经包含了上传所需的签名验证参数,不需要再在PUT请求中添加authorization头,这会干扰服务器的正常处理。 - 手动设置Content-Length不准确:requests库会自动根据上传的文件内容计算并设置
Content-Length,手动设置的值如果和实际文件长度不符(比如文件写入后大小变化),会导致服务器接收的内容为空。 - Content-Type硬编码限制:你固定设置为
image/png,如果上传的文件不是PNG格式,Discord无法正确识别文件类型,且可能拒绝处理。 - 缺乏请求状态校验:第一步POST请求创建上传会话时,如果返回错误(如token无效、频道ID错误),你直接解析响应JSON会抛出异常,且后续PUT操作毫无意义。
- 文件操作不规范:直接使用
open()而没有确保文件关闭,可能导致文件句柄泄漏,极端情况下会影响文件读取。
修正后的代码
import requests import os import mimetypes def Upload(link, channel, token): api_url = f'https://discord.com/api/v9/channels/{channel}/attachments' # 更稳妥的文件名提取方式:从链接路径中获取最后一段 file_name = link.split('/')[-1] file_id = 1 # 下载文件到本地,使用with语句自动关闭文件 response = requests.get(link) response.raise_for_status() # 检查下载请求是否成功 with open(file_name, "wb") as f: f.write(response.content) file_size = os.path.getsize(file_name) upload_payload = {"files": [{"filename": file_name, "file_size": file_size, "id": file_id}]} headers = {'authorization': token} # 创建上传会话,检查响应状态 session_response = requests.post(api_url, headers=headers, json=upload_payload) session_response.raise_for_status() # 若请求失败直接抛出异常 session_data = session_response.json() put_url = session_data['attachments'][0]['upload_url'] # 获取文件的MIME类型,替代硬编码 mime_type, _ = mimetypes.guess_type(file_name) put_headers = {} if mime_type: put_headers['Content-Type'] = mime_type # 上传文件到PUT链接,去掉多余的Authorization头,让requests自动处理Content-Length with open(file_name, 'rb') as f: put_response = requests.put(put_url, headers=put_headers, data=f) # 可选:删除本地临时文件 os.remove(file_name) return put_response
额外说明
- 上传完成后,你需要在后续发送消息的请求中,携带附件的
id和filename(来自第一步POST响应的attachments字段),格式示例:{ "content": "这是上传的附件", "attachments": [{"id": "1", "filename": "example.png"}] } - 确保你的token拥有对应频道的
attach_files权限,否则第一步POST请求会返回403错误。
内容的提问来源于stack exchange,提问作者user14436239
相关产品推荐
相关产品推荐

