如何在Node.js中直接发送包含#字符的未编码URL GET请求(无需依赖第三方NPM包)
问题描述
我知道这一情况较为特殊,但服务器端已完成实现且未集成URI编解码功能,目前无法修改。因此我需要在GET请求的URL查询参数中直接使用未编码的字符。当我请求类似https://example.com/check?id=myAccount&password=qwerty!@#这样的URL时,Node.js的http(s)模块会自动将其修改为https://example.com/check?id=myAccount&password=qwerty!@,导致我无法按预期发送数据。
请问在不使用其他NPM模块的情况下该如何解决?我已查阅Node.js官方文档但未找到答案。我使用的Node.js代码如下:
// Example : https://example.com/check?id=myAccount&password=qwerty!@# (_url, params) => { return new Promise((resolve, reject) => { if (params) { let queryParams = `?`; for (let key in params) { const value = params[key]; queryParams += `${key}=${value}&`; } queryParams = queryParams.slice(0, -1); _url += queryParams; } const options = { method: `GET`, } const req = https.request(_url, options, (res) => { // When I checked it, request URL is changed to https://example.com/check?id=myAccount&password=qwerty!@ // (Removed "#" automatically) // console.log(req) let data = ``; res.on(`data`, (d) => { data += d.toString(); process.stdout.write(d); }); res.on(`end`, () => { // process.stdout.write(d); resolve(data); }); }); req.on(`error`, (e) => { console.error(e); }); req.end(); }); }
解决方案
这个问题的根源在于:当你直接把完整URL传给https.request()时,Node.js会自动按照URL规范解析它——而#在URL里是**片段标识符(fragment identifier)**的起始标记,不属于查询参数的一部分,所以Node.js会把它从查询参数中剥离,这就是你的#消失的原因。
要绕过这个自动解析行为,你需要手动拆分URL的各个部分,直接在options对象中指定hostname、path等字段,而不是传完整URL。这样你可以完全控制path的内容,避免Node.js自动处理特殊字符。
下面是修改后的代码:
const url = require('url'); // Node.js内置模块,无需额外安装 const https = require('https'); const sendRequest = (_url, params) => { return new Promise((resolve, reject) => { // 先解析基础URL的结构,拆分出必要部分 const parsedUrl = url.parse(_url); let path = parsedUrl.path; if (params) { // 手动拼接查询参数,不做任何编码处理 let queryParams = `?`; for (let key in params) { const value = params[key]; queryParams += `${key}=${value}&`; } queryParams = queryParams.slice(0, -1); path += queryParams; } const options = { method: 'GET', hostname: parsedUrl.hostname, path: path, // 直接使用手动拼接的路径+参数,不会被自动编码 protocol: parsedUrl.protocol, port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80) } const req = https.request(options, (res) => { let data = ''; res.on('data', (d) => { data += d.toString(); process.stdout.write(d); }); res.on('end', () => { resolve(data); }); }); req.on('error', (e) => { console.error(e); reject(e); }); req.end(); }); } // 使用示例 sendRequest('https://example.com/check', { id: 'myAccount', password: 'qwerty!@#' }) .then(data => console.log('Response:', data)) .catch(err => console.error('Error:', err));
关键说明:
- 用Node.js内置的
url模块解析基础URL,拆分出hostname、protocol、path等部分,避免手动处理这些细节出错。 - 手动拼接查询参数到
path中,直接把这个path传给options,Node.js不会再对它进行自动编码或解析,这样#就能原封不动地发送到服务器。 - 处理了端口号的默认值(https默认443,http默认80),确保请求能正常连接。
这样修改后,你的请求URL就会保持你想要的原始格式,不会被Node.js自动修改了。
内容的提问来源于stack exchange,提问作者Park
相关产品推荐
相关产品推荐

