工作上遇到了一个需求, 有一个接口因为 body 量相当大, 很容易请求失败, 加上是个静默接口用户不会有任何感知, 不会手动重新发起请求. 于是就需要我们从 nginx 日志上根据收集的参数信息进行接口请求恢复, 本文即记录做该需求中遇到的若干问题和解决方案
由于需要恢复请求, 所以使用脚本, 考虑到后续维护, 用 node 脚本进行开发, 脚本功能如下:
开发中遇到的问题:
http_proxy
和 https_proxy
但 node 脚本却无法发出这个请求根据 https://github.com/nodejs/node/issues/1490 得知 node 原生不实现代理功能, 也不读取 http_proxy
变量, 原因是加入 proxy 的话 node 开发团队就需要考虑安全 / SOCKS / 证书等等一系列问题, 于是不做
但是依然可以通过很多库实现这个功能, 例如: node-global-proxy
下面的字符串 "x\xC2\x9C\xC3"
, 只是一个代指, 不是一个有意义的值, 只是为了方便解释
这个问题就比较复杂了, 主要体现在两个地方:
const body = "x\xC2\x9C\xC3"
再使用这个 body
是能成功发出请求的, js 自动完成了转码, 其参数和客户端的请求参数完全一样readline
解析出字符串 "x\xC2\x9C\xC3"
再赋值给 body
, 却没有自动转码, 传的参数是 "x\xC2\x9C\xC3"
这个字符串而不是转码后的字符串encodeURIComponent
转义再发请求, 原因这里不提, 问题在于这次使用 decodeURIComponent
后居然无法正确恢复解析转义先说第二个问题, 直接使用 decodeURIComponent("x\xC2\x9C\xC3")
无效 (报错了), 那么也就意味着 decodeURIComponent
对这些初始 utf-16 编码的字符串依然无法正确解析
然后通过搜索找到了另一个函数: querystring.escape
, 有效, 但是不是完全有效, 我发现这个函数只对部分的 utf-16 有用, 有的就无效, 这就有点奇怪了, 再仔细找原因, 发现了 node:querystring
文档里就有提到: https://nodejs.org/api/querystring.html#querystringunescapestr
By default, the querystring.unescape() method will attempt to use the JavaScript built-in decodeURIComponent() method to decode. If that fails, a safer equivalent that does not throw on malformed URLs will be used.
大概翻译下:
默认情况下 querystring.unescape() 方法会尝试用decodeURIComponent()
进行转义, 如果失败了, 那么使用更安全的方法来解决那些长得不像 url 的字符串
也就是 pass 掉
使用 decodeURIComponent(escape(s))
即可, 原来是还需要用 escape
先做一层转换呀, 不过值得一提的是 escape
函数已经被标记 deprecated
了
上面提到过, js 是 utf-16 编码的, 理论上直接支持来自 nginx 的日志参数, 直接赋值也证明了这一点 (下面 nextFetch
会直接使用 body
发出 fetch
请求)
然而如果是用 node:readline
读文件中的 'x\xC2\x9C\xC3'
却无法直接使用:
造成这个结果的原因其实是, js 代码编译过程中其实已经把第一种情况的字符串转码了, 到 runtime 时使用的已经是转码后的字符串
而第二种情况是此时 js 程序已经是 runtime 了, 此时得到的 line
自然不是代码的一部分, 就没有经过编译这个过程而未被转码, 只得到了原始的字符串
那么我们直接转码即可, 参考: https://gist.github.com/kiinlam/176ce20707336fa8278726e869e59cb1
点击这里前往 Github 查看原文,交流意见~
文档信息
版权声明:自由转载 - 非商用 - 非衍生 - 保持署名(创意共享3.0许可证)