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

node-fetch与requests请求差异排查:JS报错Python正常问题

问题排查:Node.js node-fetch POST请求500错误 vs Python requests正常

问题背景

两段逻辑看似一致的POST请求代码,Python版使用requests库可正常获取响应,但Node.js版使用node-fetch时返回500内部服务器错误,需定位差异及报错原因。

相关代码

Node.js 代码(报错版本)

import fetch from 'node-fetch';

const url = "http://host3.dreamhack.games:15592/img_viewer"
const imageUrl = "/static/dream.png"
const data = {
    "url": imageUrl
}
const res = await fetch(url, {
    method: "POST",
    body: JSON.stringify(data)
})
const text = await res.text()
console.log(text)

// 返回内容:
// <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
// <title>500 Internal Server Error</title>
// <h1>Internal Server Error</h1>
// <p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>

Python 代码(正常版本)

import requests

url = "http://host3.dreamhack.games:15592/img_viewer"
imageUrl = "/static/dream.png"
data = {
    "url": imageUrl
}
response = requests.post(url, data=data)
print(response.text)

后端 Flask 服务代码

@app.route("/img_viewer", methods=["GET", "POST"])
def img_viewer():
    if request.method == "GET":
        return render_template("img_viewer.html")
    elif request.method == "POST":
        url = request.form.get("url", "")
        urlp = urlparse(url)
        if url[0] == "/":
            url = "http://localhost:8000" + url
        elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
            data = open("error.png", "rb").read()
            img = base64.b64encode(data).decode("utf8")
            return render_template("img_viewer.html", img=img)
        try:
            data = requests.get(url, timeout=3).content
            img = base64.b64encode(data).decode("utf8")
        except:
            data = open("error.png", "rb").read()
            img = base64.b64encode(data).decode("utf8")
        return render_template("img_viewer.html", img=img)

差异分析

核心差异在于请求数据格式与Content-Type头:

  • Python requests.post(url, data=data):默认将数据编码为application/x-www-form-urlencoded格式的表单数据,自动设置对应Content-Type头,后端request.form.get("url")可以正确提取参数。
  • Node.js fetch用JSON.stringify(data)作为body:默认Content-Type为text/plain,后端request.form无法解析JSON格式的数据,因此url = request.form.get("url", "")得到的是空字符串。

报错原因

后端代码中,当url为空字符串时,执行if url[0] == "/"会抛出TypeError(空字符串没有索引0),而后端的except块仅捕获requests.get相关的异常,未处理此类型错误,最终触发Flask的500内部服务器错误。

修复方案

将Node.js请求改为发送application/x-www-form-urlencoded格式的表单数据,有两种实现方式:

方式1:使用URLSearchParams构造表单数据

import fetch from 'node-fetch';
import { URLSearchParams } from 'url';

const url = "http://host3.dreamhack.games:15592/img_viewer"
const imageUrl = "/static/dream.png"
const params = new URLSearchParams();
params.append('url', imageUrl);

const res = await fetch(url, {
    method: "POST",
    body: params
})
const text = await res.text()
console.log(text)

方式2:手动编码表单数据并设置Content-Type

import fetch from 'node-fetch';

const url = "http://host3.dreamhack.games:15592/img_viewer"
const imageUrl = "/static/dream.png"
const data = `url=${encodeURIComponent(imageUrl)}`;

const res = await fetch(url, {
    method: "POST",
    body: data,
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    }
})
const text = await res.text()
console.log(text)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 02:06:05