Express.js中Google OAuth2重定向URL的req.query为空问题求助
嘿,这个问题其实是URL里的哈希(#)特性导致的,我来给你拆解清楚:
核心原因
浏览器在发送请求给服务器时,只会把#之前的部分发送出去,#后面的所有内容(也就是锚点部分)会留在浏览器本地,不会传递到服务器端。
你第一次的重定向URL是:
http://localhost:997/?#state=pass-through%20value&access_token=ya29.ImC6B1g9LYsf5siso8n_UphOFB0SXc5dqsm6LqHRWXbtNHisEblxjeLoYtGgwSVtCTGxOjjODiuTyH7VCHoZCEfUd_&token_type=Bearer&expires_in=3599&scope=https://www.googleapis.com/auth/youtube.readonly
这里?后面直接跟着#,服务器收到的请求路径其实只有http://localhost:997/,没有任何查询参数,所以req.query是空对象{}完全正常。
而你去掉#state=...之后,所有参数都放在了?后面的查询字符串里,这部分会被浏览器完整发送给服务器,Express就能正常解析到req.query中。
解决办法
你有两种思路来解决这个问题:
1. 调整Google OAuth的重定向配置(推荐)
Google OAuth默认应该是把state和access_token等参数放在查询字符串(?后面)而不是哈希里的,可能你在配置OAuth的时候不小心选了隐式授权模式(Implicit Flow)?这种模式会把token放在哈希里。
如果你的应用是服务端应用,建议改用授权码模式(Authorization Code Flow),这种模式会返回授权码到查询参数里,然后服务器用授权码去换token,更安全也不会出现这个问题。
2. 前端解析哈希参数后传给服务器
如果暂时没法改OAuth模式,那只能通过前端JavaScript来读取哈希里的参数,再传递给服务器:
修改你的Express路由,先返回一个处理页面:
var express = require('express'), app = express(), port = process.env.PORT || 997; app.get("/", (req, res, next) => { // 返回一个包含脚本的页面,用来解析哈希参数 res.send(` <!DOCTYPE html> <html> <body> <script> // 解析哈希中的参数 const hashStr = window.location.hash.slice(1); // 去掉开头的# const params = new URLSearchParams(hashStr); // 把参数通过查询字符串传给服务器的/process-token路由 window.location.href = '/process-token?' + params.toString(); </script> </body> </html> `); }); app.get("/process-token", (req, res) => { console.log(req.query); // 这里就能拿到access_token、state等参数了 res.send("Token received! Check server console."); }); app.listen(port, ()=>{ console.log("Server on port: " + port); });
这样当用户被重定向到http://localhost:997/?#...时,前端脚本会自动解析哈希里的参数,跳转到/process-token并带上这些参数,服务器就能通过req.query获取到了。
总结
你的Express代码本身没有问题,问题出在URL的哈希部分不会被服务器接收这个特性上。优先建议调整OAuth的授权模式,这样更符合服务端应用的安全规范;如果只能用隐式模式,就用前端解析的方式来传递参数。
内容的提问来源于stack exchange,提问作者Bartosz Stefańczyk

