node.js oauth-1.0a 适用于 Twitter API v1.1 但不适用于 v2

问题描述

我是 found 这个函数生成 oauth-1.0a 头:

// auth.js

const crypto = require("crypto");
const OAuth1a = require("oauth-1.0a");

function auth(request) {
  const oauth = new OAuth1a({
    consumer: {
      key: process.env.TWITTER_API_KEY,secret: process.env.TWITTER_API_SECRET_KEY,},signature_method: "HMAC-SHA1",hash_function(baseString,key) {
      return crypto.createHmac("sha1",key).update(baseString).digest("base64");
    },});

  const authorization = oauth.authorize(request,{
    key: process.env.TWITTER_ACCESS_TOKEN,secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,});

  return oauth.toHeader(authorization).Authorization;
}

module.exports = auth;

如果我用 Twitter API v1.1 试试,效果很好:

// v1.js

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = "https://api.twitter.com/1.1/favorites/create.json";
const method = "POST";
const params = new URLSearchParams({
  id: "1397568983931392004",});

axios
  .post(url,undefined,{
    params,headers: {
      authorization: auth({
        method,url: `${url}?${params}`,}),})
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

但如果我用 Twitter API v2 试试:

// v2.js

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = {
  tweet_id: "1397568983931392004",};

axios
  .post(url,data,{
    headers: {
      authorization: auth({
        method,url,})
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

它失败了:

{
  title: 'Unauthorized',type: 'about:blank',status: 401,detail: 'Unauthorized'
}

我尝试按照建议的 here 对请求正文进行编码,但得到相同的错误

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");
const querystring = require("querystring");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = percentEncode(
  querystring.stringify({
    tweet_id: "1397568983931392004",})
);

function percentEncode(string) {
  return string
    .replace(/!/g,"%21")
    .replace(/\*/g,"%2A")
    .replace(/'/g,"%27")
    .replace(/\(/g,"%28")
    .replace(/\)/g,"%29");
}

axios
  .post(url,{
    headers: {
      "content-type": "application/json",authorization: auth({
        method,})
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

如果使用 Postman 进行测试,两个端点(1.1 和 2)可以使用相同的凭据正常工作。

关于我在使用 v2 时做错了什么或如何让它与 Twitter API v2 一起工作的任何想法?

我怀疑这与请求正文有关,因为这是两个请求之间的主要区别,但一直无法使其工作。

解决方法

弄清楚,生成授权头时不应包含请求正文:

require("dotenv").config();
const axios = require("axios");
const auth = require("./auth");

const url = `https://api.twitter.com/2/users/${process.env.TWITTER_USER_ID}/likes`;
const method = "POST";
const data = {
  tweet_id: "1397568983931392004",};

axios
  .post(url,data,{
    headers: {
      authorization: auth({
        method,url,}),},})
  .then((data) => {
    return console.log(data);
  })
  .catch((err) => {
    if (err.response) {
      return console.log(err.response);
    }
    console.log(err);
  });

基本上,当向 Twitter API v1.1 发出 post 请求时,数据应该被编码,应该用于生成授权标头,并且 post 请求应该作为 application/x-www-form-urlencoded 发送。

向 Twitter API v2 发出发布请求时,数据不应被编码,不应在生成授权标头时包含在内,并且必须作为 application/json 发送。

希望这对其他人有所帮助。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...