使用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); } }
可能原因及排查思路
URL编码丢失:
Express会自动解码路径中的URL编码字符,客户端传的%7C会被解码成|,但代码里直接把这个原始|拼接到转发URL里,没有重新编码。部分后端服务会把路径中的|视为非法字符(虽属于RFC规范允许的分隔符,但很多服务会限制使用),直接返回400。而逗号(,)同样是分隔符,但多数服务允许通过,所以没触发错误。上游服务参数校验:
你转发的上游服务(process.env.URL指向的服务)可能对value参数做了字符白名单限制,明确禁止|或其编码形式,收到后直接返回400。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
相关产品推荐
相关产品推荐

