使用twitter-v2.js发送回复时遭遇401 Unauthorized错误求助
核心问题分析
你遇到的401错误最可能是因为回复推文未@原作者,Twitter API v2强制要求回复内容必须包含被回复推文的作者用户名,否则会直接拒绝请求。此外还有几处代码细节和配置需要核对。
具体修复步骤
1. 回复文本必须包含原作者@用户名
修改搜索请求以获取推文作者ID,再批量获取用户名,将其添加到回复内容中:
// 修改搜索请求,添加tweet.fields参数获取作者ID const { data } = await Bot2.get('tweets/search/recent', { query: TWITTER_SEARCH_PHRASE, max_results: TWITTER_SEARCH_MAX_RESULTS, 'tweet.fields': 'author_id' }); // 批量获取所有推文作者的用户名,避免多次API请求 const authorIds = data.map(tweet => tweet.author_id); const { data: users } = await Bot2.get('users', { ids: authorIds.join(',') }); const userIdToName = {}; users.forEach(user => { userIdToName[user.id] = user.username; }); // 生成带@作者的回复文本 var authorUsername = userIdToName[data[i].author_id]; var textToReply = `Hey @${authorUsername} ${TWEETS_TO_REPLY[Math.floor(Math.random()*TWEETS_TO_REPLY.length)]}`;
2. 确认OAuth 1.0a凭证有效性
- 再次核对
TWITTER_ACCESS_TOKEN和TWITTER_ACCESS_TOKEN_SECRET:这两个凭证必须来自已授权你的应用获取读写权限的用户,不是应用级Bearer Token对应的凭证。 - 登录Twitter开发者平台,确认你的应用权限确实设置为「读写」,且用户授权流程已完整执行(access token是通过OAuth授权流程生成的,不是仅创建应用时的密钥)。
3. 修正代码中的同步文件读取错误
fs.readFileSync是同步方法,不需要加await,否则会导致不必要的Promise等待:
// 错误写法 // var fileData = await fs.readFileSync(DB_FILE, 'utf8'); // 正确写法 var fileData = fs.readFileSync(DB_FILE, 'utf8');
4. 可选:明确指定API版本
部分版本的twitter-v2库需要明确指定API版本,可修改Bot实例初始化代码:
var Bot = new Twitter({ consumer_key: TWITTER_CONSUMER_KEY, consumer_secret: TWITTER_CONSUMER_SECRET, access_token_key: TWITTER_ACCESS_TOKEN, access_token_secret: TWITTER_ACCESS_TOKEN_SECRET, version: '2' // 明确指定使用API v2 });
完整修改后的关键代码片段
async function BotStart() { console.log("> Twitter bot is running (" + Date() + ")...") // 搜索推文并获取作者ID const { data } = await Bot2.get('tweets/search/recent', { query: TWITTER_SEARCH_PHRASE, max_results: TWITTER_SEARCH_MAX_RESULTS, 'tweet.fields': 'author_id' }); console.log(data); // 处理本地数据库文件 var bot_db = []; if (!fs.existsSync(DB_FILE)) { fs.closeSync(fs.openSync(DB_FILE, 'w')); } var fileData = fs.readFileSync(DB_FILE, 'utf8'); fileData = fileData.trim(); if (fileData !== "") { bot_db = fileData.split("\n"); } var processed_tweets = []; // 批量获取作者用户名 const authorIds = data.map(tweet => tweet.author_id); const { data: users } = await Bot2.get('users', { ids: authorIds.join(',') }); const userIdToName = {}; users.forEach(user => { userIdToName[user.id] = user.username; }); // 遍历处理推文 for (var i = 0; i < data.length; i++) { var id = data[i].id; if (bot_db.indexOf(id) === -1) { processed_tweets.push(id); // 记录已处理推文ID fs.appendFile(DB_FILE, id + "\n", function (err) { if (err) { console.log("写入数据库文件失败: " + DB_FILE); } else { console.log("已处理推文ID: " + id); } }); // 生成回复内容并发送 var authorUsername = userIdToName[data[i].author_id]; var textToReply = `Hey @${authorUsername} ${TWEETS_TO_REPLY[Math.floor(Math.random()*TWEETS_TO_REPLY.length)]}`; try { var replyData = await Bot.post('tweets', { text: textToReply, in_reply_to_tweet_id: id }); console.log("回复成功: " + textToReply); } catch (error) { console.log("回复错误详情: ", error); } } } // 输出处理结果 if (processed_tweets.length > 0) { console.log("> 本次处理推文ID列表: " + processed_tweets); } else { console.log("> 本次无新推文需要处理。"); } }
内容的提问来源于stack exchange,提问作者koukotsu
相关产品推荐
相关产品推荐

