为何本地Windows请求返回JSON,Linux服务器返回HTML?
问题描述
用Node.js开发REST API时,使用request包调用第三方API https://hahu.io/api/send/otp,本地Windows机器能正常获取JSON响应,但部署到Ubuntu 22服务器后,返回的是人机验证HTML内容,导致业务逻辑崩溃,更换Axios后问题依旧。
本地运行代码:
await request.post( encodeURI(`https://hahu.io/api/send/otp`), { form: { secret: process.env.HAHU_API_KEY, mode: 'devices', type: 'sms', device: process.env.HAHU_DEVICE_KEY, sim: '1', phone: `+251${phone}`, message: 'Your OTP code is {{otp}}', }, }, (err, response, data) => { if (err) { console.log(err) } console.log(data) } )
本地正常返回的JSON结果:
{ "status": 200, "message": "OTP has been sent!", "data": { "phone": "+251900000009", "message": "Your OTP code is 552614", "otp": 552614 } }
服务器返回的HTML内容:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="robots" content="noindex, nofollow"> <title>One moment, please...</title> <style> body { background: #F6F7F8; color: #303131; font-family: sans-serif; margin-top: 45vh; text-align: center; } </style> </head> <body> <h1>Please wait while your request is being verified...</h1> <form id="wsidchk-form" style="display:none;" action="/z0f76a1d14fd21a8fb5fd0d03e0fdc3d3cedae52f" method="get"> <input type="hidden" id="wsidchk" name="wsidchk"/> </form> <script> (function () { var west = +((+!+[] + !![]) + (+!+[] + !![] + !![] + !![] + !![] + !![] + []) + (+!+[] + !![] + !![] + !![]) + (+!+[] + !![] + !![] + !![] + !![] + !![] + []) + (+!+[] + !![] + !![] + !![] + !![] + !![]) + (+![] + []) + (+!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![])), east = +((+!+[] + !![]) + (+!+[] + !![] + !![] + []) + (+!+[]) + (+!+[] + !![] + !![] + !![] + !![] + !![] + !![] + !![] + []) + (+!+[] + !![]) + (+![] + [])), x = function () { try { return !!window.addEventListener; } catch (e) { return !!0; } }, y = function (y, z) { x() ? document.addEventListener("DOMContentLoaded", y, z) : document.attachEvent("onreadystatechange", y); }; y(function () { document.getElementById('wsidchk').value = west + east; document.getElementById('wsidchk-form').submit(); }, false); })(); </script> </body> </html>
问题原因
- 目标API服务器启用了人机验证机制,服务器IP属于云主机IP池,常被爬虫等自动化请求使用,因此被判定为非终端用户请求,触发拦截;而本地个人机器IP属于正常用户IP范围,未触发验证规则。
- 请求头缺失浏览器标准标识(如
User-Agent、Accept等),进一步被服务器判定为自动化请求。
解决方法
1. 补充完整请求头,模拟浏览器请求
无论使用request还是Axios,添加符合浏览器标准的请求头,示例(Axios版本):
const axios = require('axios'); const response = await axios.post('https://hahu.io/api/send/otp', { secret: process.env.HAHU_API_KEY, mode: 'devices', type: 'sms', device: process.env.HAHU_DEVICE_KEY, sim: '1', phone: `+251${phone}`, message: 'Your OTP code is {{otp}}', }, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'application/json, text/plain, */*', 'Accept-Language': 'en-US,en;q=0.9' } }); console.log(response.data);
2. 处理人机验证逻辑
返回的HTML中包含JS计算wsidchk参数并自动提交表单的逻辑,可通过两种方式处理:
- 手动计算参数:解析JS代码得出
west=74777718、east=731871,总和为75509589,携带该参数重新请求目标API。 - 使用Headless浏览器:通过Puppeteer自动加载页面完成验证,获取最终JSON响应,示例:
const puppeteer = require('puppeteer'); const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setExtraHTTPHeaders({ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' }); // 提交初始请求 await page.goto('https://hahu.io/api/send/otp', { method: 'POST', postData: new URLSearchParams({ secret: process.env.HAHU_API_KEY, mode: 'devices', type: 'sms', device: process.env.HAHU_DEVICE_KEY, sim: '1', phone: `+251${phone}`, message: 'Your OTP code is {{otp}}', }).toString(), headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }); // 等待验证完成,获取最终响应 const finalResponse = await page.waitForResponse(res => res.url().includes('/api/send/otp') && res.status() === 200); const data = await finalResponse.json(); console.log(data); await browser.close();
3. 申请API白名单
联系hahu.io官方,将服务器IP加入API请求白名单,彻底绕过验证机制。
4. 更换服务器IP
若服务器IP已被列入黑名单,可更换服务器实例或使用代理IP发起请求。
内容的提问来源于stack exchange,提问作者Amansisa Tadese Gudina
相关产品推荐
相关产品推荐

