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

使用node-fetch发起POST请求传入%7C时出现400错误求助

Express接口传入URL编码竖线%7C返回400错误排查

问题现象

用Express+node-fetch编写的转发接口,传入逗号(,)或字符串"tab"作为value路径参数时,请求正常返回200;但传入URL编码后的竖线%7C(对应原始字符|)时,直接返回400 Bad Request。示例请求:

  • 正常:https://xxx/name/NAME/value/,
  • 正常:https://xxx/name/NAME/value/tab
  • 异常:https://xxx/name/NAME/value/%7C

涉事代码

const fetch = require("node-fetch").default;

let iApi = express.Router();

iApi.post("/update/:name/:value", async (req, res) => {
    const name = req.params["name"];
    const value = req.params["value"];

    const headers = { ...req.headers };
    const url = `${process.env.URL}/name/${name}/value/${value}`;

    const options = {
        url: url,
        method: "post",
        headers: headers,
        gzip: true,
    };

    try {
        const response = await fetch(url, options);
        handleResponseNoBody(
            response.ok,
            response.status,
            response.body,
            res,
            url
        );
    } catch (err) {
        handleResponseNoBody(false, 500, err, res, url);
    }
});

function handleResponseNoBody(ok, status, data, res, url) {
    const loggerOpts = Object.assign({}, LOG_DEFAULTS, {
        endpoint_url: url,
        application: "app1",
    });

    if (!ok) {
        loggerOpts.description = `${url} error retrieving endpoint`;
        loggerOpts.response_obj = { status_code: 500 };
        loggerOpts.err = data;
        logger.error(loggerOpts);
        res.status(status).send(data);
    } else if (status === 200) {
        loggerOpts.description = `${url} return 200`;
        loggerOpts.response_obj = { status_code: 200 };
        loggerOpts.response_body = data;
        logger.info(loggerOpts);
        res.status(status).send(data);
    } else {
        loggerOpts.description = `${url} endpoint did not return 200 status`;
        loggerOpts.error = data;
        loggerOpts.response_obj = { status_code: status };
        logger.info(loggerOpts);
        res.status(status).send(data);
    }
}

可能原因及排查思路

  1. URL编码丢失:
    Express会自动解码路径中的URL编码字符,客户端传的%7C会被解码成|,但代码里直接把这个原始|拼接到转发URL里,没有重新编码。部分后端服务会把路径中的|视为非法字符(虽属于RFC规范允许的分隔符,但很多服务会限制使用),直接返回400。而逗号(,)同样是分隔符,但多数服务允许通过,所以没触发错误。

  2. 上游服务参数校验:
    你转发的上游服务(process.env.URL指向的服务)可能对value参数做了字符白名单限制,明确禁止|或其编码形式,收到后直接返回400。

  3. Express/Node.js路径解析限制:
    检查Express路由配置或Node.js本身的URL处理逻辑,是否默认拦截了包含|的路径请求,导致请求还没到转发逻辑就被拦截返回400。

验证修复方案

  • 重新编码参数:把拼接URL的代码改成const url = ${process.env.URL}/name/${encodeURIComponent(name)}/value/${encodeURIComponent(value)};,重新对参数做URL编码后再转发,测试是否解决400问题。
  • 直接调用上游服务:手动构造上游服务的请求URL(比如${process.env.URL}/name/NAME/value/%7C),直接发送请求看是否返回400,以此判断是上游服务的问题还是当前转发代码的问题。
  • 查看上游日志:如果能访问上游服务的日志,直接看400错误的具体报错信息,比如是“参数包含非法字符”还是“路径格式无效”,精准定位原因。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:39:52