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

使用requests调用Twitter API时出现Error 400 Bad Request问题排查

问题原因分析

你的400 Bad Request错误主要来自以下几个关键问题:

1. OAuth请求头格式完全错误

OAuth 1.0的授权头应该是单个Header字段,格式为OAuth oauth_consumer_key="xxx", oauth_nonce="xxx", oauth_signature="xxx", ...,而不是把每个OAuth参数拆分成独立的Header键。你的代码里把每个参数都作为单独的Header,这会被API识别为无效格式。

2. OAuth参数赋值错误

  • 你把oauth_token_secret错误赋值给了oauth_token字段,两者是完全不同的参数:oauth_token是第一个程序生成的令牌值,oauth_token_secret是对应的密钥。
  • 你直接用oauth_token作为oauth_signature,这完全不符合要求——签名需要通过HMAC-SHA1算法,结合请求方法、请求URL、所有请求参数、consumer_secret和oauth_token_secret生成,不能直接用令牌代替。

3. 缺少必要的签名生成逻辑

手动构造OAuth 1.0签名需要严格遵循算法步骤,包括参数排序、编码、拼接基字符串、用密钥签名等,你的代码完全跳过了这个关键步骤,导致签名无效。


改进方案

方案一:继续使用requests_oauthlib(推荐,先验证功能再移植)

既然你已经用OAuth1Session生成了合法的令牌,直接用这个库来发送请求会自动处理OAuth签名和头格式,避免手动构造的错误:

import os
import json
from requests_oauthlib import OAuth1Session

consumer_key = os.environ.get("CONSUMER_KEY")
consumer_secret = os.environ.get("CONSUMER_SECRET")

# 替换成第一个程序生成的令牌
oauth_token = "<your_oauth_token>"
oauth_token_secret = "<your_oauth_token_secret>"

payload = {"text": "Hello world1!"}

# 初始化OAuth会话
oauth = OAuth1Session(
    consumer_key,
    client_secret=consumer_secret,
    resource_owner_key=oauth_token,
    resource_owner_secret=oauth_token_secret
)

response = oauth.post("https://api.twitter.com/2/tweets", json=payload)

if response.status_code != 201:
    raise Exception(f"Request error: {response.status_code} {response.text}")

print(f"Response code: {response.status_code}")
print(json.dumps(response.json(), indent=4, sort_keys=True))

方案二:手动构造请求(适合嵌入式移植场景)

如果必须手动构造请求,需要修正以下几点:

  1. 合并OAuth参数到单个Header:
    正确的Header格式示例:
    import string
    import random
    import time
    import requests
    import hmac
    import hashlib
    import base64
    from urllib.parse import quote, urlencode
    
    def generate_oauth_signature(method, url, oauth_params, payload, consumer_secret, token_secret):
        # 合并所有参数(OAuth参数和请求体参数)
        all_params = oauth_params.copy()
        all_params.update(payload)
        # 按参数名排序并编码
        sorted_params = sorted(all_params.items())
        encoded_params = urlencode(sorted_params, quote_via=quote)
        # 构造基字符串
        base_string = f"{method.upper()}&{quote(url)}&{quote(encoded_params)}"
        # 构造签名密钥
        signing_key = f"{quote(consumer_secret)}&{quote(token_secret)}"
        # 生成HMAC-SHA1签名并Base64编码
        signature = hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha1).digest()
        return base64.b64encode(signature).decode()
    
    # 生成OAuth参数
    oauth_params = {
        "oauth_consumer_key": consumer_key,
        "oauth_nonce": "".join(random.choice(string.ascii_letters + string.digits) for _ in range(32)),
        "oauth_signature_method": "HMAC-SHA1",
        "oauth_timestamp": str(int(time.time())),
        "oauth_token": oauth_token,
        "oauth_version": "1.0"
    }
    # 生成合法签名
    oauth_params["oauth_signature"] = generate_oauth_signature(
        "POST",
        "https://api.twitter.com/2/tweets",
        oauth_params,
        payload,
        consumer_secret,
        oauth_token_secret
    )
    # 拼接成单个Authorization头
    auth_header = "OAuth " + ", ".join([f'{k}="{v}"' for k, v in oauth_params.items()])
    headers = {"Authorization": auth_header, "Content-Type": "application/json"}
    
    # 发送请求
    response = requests.post("https://api.twitter.com/2/tweets", headers=headers, json=payload)
    
  2. 修正参数对应关系:确保oauth_token和oauth_token_secret赋值正确,不要搞混。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 03:10:28