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

Express解析request.query百分号编码异常如何获取原始传参

问题原因

这个报错和Express、底层的qs库没有关系,本质是你发送的URL不符合百分号编码规范。
按照编码规则,%是转义序列的起始标识,只要出现在URL里就必须被编码为%25,否则解析器会默认把%和它后面紧跟的两个字符当做一个转义单元处理。你发的请求http://localhost/resource?offer=20% discount里,%后面直接跟了空格,不满足“%后接两位十六进制字符”的合法转义规则,自然会解析出错,调用decodeURIComponent也会报URI格式错误。
另外你提到的“浏览器不自动编码%”的疑惑,核心是浏览器的自动编码只作用于受控场景:比如原生表单提交、调用fetch/XMLHttpRequest时传入参数对象由API自动拼接、地址栏输入内容后回车由浏览器自动规整。如果你是手动拼接URL字符串直接写了未转义的%、或者用接口测试工具手动输入了带裸%的地址,客户端不会主动帮你修正非法格式,会直接把错误的请求发出去。
顺带提一句,你贴的解析结果是{ badge: '20%%20discount' },参数名从offer变成了badge,大概率是笔误或者你代码里有其他逻辑改写了query,默认解析逻辑不会随便修改参数名。

解决方法

分两种场景处理:

场景1:你能控制请求发送端(推荐)

这是最彻底的解决方案,从源头保证URL格式合法,不需要改服务端任何代码。
所有query参数在拼接前统一做编码,不要手动拼接带特殊字符的裸字符串:

  • 前端发请求优先用URLSearchParams处理参数,它会自动完成所有特殊字符的转义:
const params = new URLSearchParams()
params.append('offer', '20% discount')
// 最终生成的query是 offer=20%25%20discount,Express默认解析就能直接拿到正确的"20% discount"
fetch(`/resource?${params.toString()}`)
  • 如果要手动拼接URL,记得对每个参数的键和值单独调用encodeURIComponent转义:
const offerValue = encodeURIComponent('20% discount') // 转义结果为20%25%20discount
const requestUrl = `/resource?offer=${offerValue}`

场景2:无法控制请求端,必须兼容非法格式URL

如果你的服务必须接收这类不符合规范的请求,就关掉Express默认的query解析,自己写容错逻辑处理原始URL:

  1. 首先关闭Express默认的解析器:
const express = require('express')
const app = express()
app.set('query parser', false) // 关闭后req.query会为空,原始query串可以从req.url里拿到
  1. 加一个自定义解析中间件,做容错解码,遇到非法转义序列不抛错,保留原始内容:
// 容错解码:遇到非法%转义时不抛出异常
function safeDecode(str) {
  return str
    .replace(/\+/g, ' ') // 先把表单格式的+替换为空格
    .replace(/%([0-9A-Fa-f]{2})/g, match => {
      try {
        return decodeURIComponent(match)
      } catch {
        return match
      }
    })
    .replace(/%(?![0-9A-Fa-f]{2})/g, '%') // 处理单独存在的非法%
}

// 注册query解析中间件
app.use((req, res, next) => {
  const queryPart = req.url.split('?')[1] || ''
  req.query = Object.fromEntries(
    queryPart.split('&').filter(Boolean).map(kv => {
      const [key, val = ''] = kv.split('=')
      return [safeDecode(key), safeDecode(val)]
    })
  )
  next()
})

加上这段逻辑之后,哪怕请求是?offer=20% discount这种非法格式,也能正确解析出req.query.offer的值为20% discount。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:27:27