Node.js使用url.parse解析带特殊字符的Postgres连接串时auth为null如何解决
问题根因
- 解析失效的本质是密码里的特殊字符没有做URL编码,直接破坏了URL本身的语法结构。
- 按照URL通用规范,
#、@、:这类字符属于保留字符,每个都有固定的语法作用:#是URL片段(hash)的起始分隔符,只要出现在非编码位置,解析器会直接把它后面的所有内容都判定为片段内容,不再属于前面的用户信息、域名、端口部分。@是用户信息(也就是登录用的账号密码段)和主机地址的分隔符,非编码状态下只能出现在用户信息的末尾,用来分隔账号密码和后面的域名。
- 结合给出的连接串具体拆解:
- 密码内容是
pas#%w#@rd,未编码的#触发了片段分隔逻辑,解析器碰到第一个#时,直接把后面的全部内容划进hash片段。原本应该作为userinfo分隔符的@现在被归到了hash片段里,在实际的有效解析段(//后面到#之前的部分)只剩下someuser:pas,完全没有@标识。 - 因为没有
@分隔标记,解析器根本不会识别到账号密码段,反而会把someuser:pas当成主机:端口的结构解析。又因为pas不是合法的数字端口,整个主机部分的解析失败,最终返回的auth字段、host字段全都是null,自然会触发读取null执行split方法的报错。
- 密码内容是
- 把
#、%这类特殊字符去掉之后,@就回到了有效解析段里,作为账号密码和主机的分隔符,解析器就能正确识别账号:密码@主机:端口的结构,程序自然正常运行。
正确的处理方式
- 构造连接串时必须对特殊字符做编码
用户名、密码里如果包含URL保留字符,或者非ASCII字符,必须做百分号编码,不能直接拼在连接串里。比如你的密码里#要转成%23,@要转成%40,%本身要转成%25,原始密码pas#%w#@rd编码之后变成pas%23%25w%23%40rd,对应的合法连接串为:postgres://someuser:pas%23%25w%23%40rd@rd-some-db.cgosdsd8op.us-east-1.rds.amazonaws.com:5432 - 解析时不要手动拆分auth字段
就算连接串编码正确,直接用auth.split(':')也有隐患——如果密码本身包含冒号,简单拆分会把密码拆错。推荐两种更可靠的解析方式:- 优先用WHATWG标准的内置
URL类解析,它会自动拆分用户信息、自动处理编码,比老式的url.parse对非HTTP协议的兼容性更好:const connUrl = new URL('postgres://someuser:pas%23%25w%23%40rd@rd-some-db.cgosdsd8op.us-east-1.rds.amazonaws.com:5432'); // 直接取内置拆分好的字段,自动解码还原真实的账号密码 const user = connUrl.username; const password = connUrl.password; const host = connUrl.hostname; const port = connUrl.port; - 如果是使用pg这类Postgres Node客户端连接数据库,根本不需要手动拆分连接串,直接把连接串传入客户端配置即可,客户端本身就内置了合规的连接串解析逻辑,能避免手动拆分带来的各类边界问题。
- 优先用WHATWG标准的内置
内容的提问来源于stack exchange,提问作者Ted
相关产品推荐
相关产品推荐

