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

为何本地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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:35:30