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

使用Scribe Java调用Twitter v2 API POST关注请求遇401未授权

问题分析与解决

核心原因

OAuth 1.0a 签名要求请求的**所有参数(包括请求体中的参数)**都要纳入签名计算。你的GET请求成功是因为参数都在URL中,Scribe会自动将其加入签名基串;但POST请求使用application/json格式时,Scribe的addBodyParameter()方法仅适用于application/x-www-form-urlencoded编码的表单参数,不会将JSON请求体的内容纳入签名计算,导致Twitter验证签名时不匹配,返回401未授权。

解决方案

方案1:改用表单编码格式发送请求

Twitter API支持接收application/x-www-form-urlencoded格式的POST参数,这种格式下Scribe能正确处理签名:

public boolean followUser(String accountId, String userId) throws IOException, ExecutionException, InterruptedException {
    OAuth1AccessToken twitterUserAccessToken = getTwitterUserAccessToken();

    request = new OAuthRequest(Verb.POST, BASE_URL + "/users/" + accountId + "/following");
    // 改用表单编码的Content-Type
    request.addHeader("Content-Type", "application/x-www-form-urlencoded");
    // 直接添加表单参数,Scribe会自动将其纳入签名
    request.addBodyParameter("target_user_id", userId);

    service.signRequest(twitterUserAccessToken, request);
    com.github.scribejava.core.model.Response response = service.execute(request);
    System.out.println(response.getBody());

    return response.isSuccessful();
}

方案2:手动处理JSON请求体的签名(适合必须用JSON的场景)

如果必须使用JSON格式,需要手动计算请求体的SHA-1哈希,并将其作为oauth_body_hash参数加入OAuth签名流程:

import java.security.MessageDigest;
import java.util.Base64;

public boolean followUser(String accountId, String userId) throws IOException, ExecutionException, InterruptedException, NoSuchAlgorithmException {
    OAuth1AccessToken twitterUserAccessToken = getTwitterUserAccessToken();

    // 构造JSON请求体
    String jsonBody = "{\"target_user_id\":\"" + userId + "\"}";
    request = new OAuthRequest(Verb.POST, BASE_URL + "/users/" + accountId + "/following");
    request.addHeader("Content-Type", "application/json");
    // 设置原始JSON请求体
    request.setPayload(jsonBody);

    // 计算JSON体的SHA-1哈希并Base64编码
    MessageDigest md = MessageDigest.getInstance("SHA-1");
    byte[] hashBytes = md.digest(jsonBody.getBytes("UTF-8"));
    String bodyHash = Base64.getEncoder().encodeToString(hashBytes);

    // 将body hash加入OAuth参数,让Scribe签名时包含这个值
    request.addOAuthParameter("oauth_body_hash", bodyHash);

    service.signRequest(twitterUserAccessToken, request);
    com.github.scribejava.core.model.Response response = service.execute(request);
    System.out.println(response.getBody());

    return response.isSuccessful();
}

补充说明

关于你提到的RestAssured也出现问题,大概率是同样的签名逻辑问题——没有将JSON请求体纳入OAuth1签名计算,按照上述方案调整签名逻辑即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 02:10:51