背景
有一个node项目,由于某seo的原因,需要把某些http
请求重定向到https
。
过程
需求很简单,开搞~
因为node是express框架的,这种操作理所应该在中间件中做, 在我们的入口文件中添加:
var protocolRedirect = function (req, res, next) {
const { protocol, header, originalUrl} = req;
// 如果是线上环境,并且是http协议的话就跳走
if (isOnline && protocol==='http') {
res.redirect(`https://${headers.host}${originalUrl}`);
}
next()
};
app.use(protocolRedirect);
Nice,本地调试,没有问题~ 部署到沙箱环境。
这里说一下我们的沙箱环境有一层nginx转发,支持https以及http协议进行接口请求。
部署完毕,check一下~ 本地用switch host配置下域名ip的映射关系,访问服务对应的页面 http://域名.com/home
,发现控制台不停的发302重定向请求。就很奇怪,,明明代码里会让他重定向到https
,之后就不会重定向了啊,查了查服务器日志req.protocol
确实是获取到了请求的协议时http
。
难道是重定向https那里有问题了么?直接用浏览器访问https://域名.com/home
试了一下 ,居然日志显示此时req.protocol
还是http
。。。
这可就不对了啊!!明明请求的是https啊!!
if (isOnline && protocol==='http') // 确实这里有问题
解决
打开google,一顿搜索,发现这种在(nginx)转发代理后的服务需要激活trust proxy
,这样才能使我们的服务对后面的代理进行信任从而拿到经过nginx修改过的protocol
等信息。
图片来源 stackoverflow
结合下实际情况,我们的沙箱有一层nginx,当https请求对应的域名解析到沙箱nginx之后,nginx会将请求的X-Forwarded-Proto
进行修改(改为https),相应的影响我们取req.protocol
。以下是我们nginx部分配置。
location / {
...
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $xff;
proxy_set_header X-Real-IP $remote_address;
// $scheme就是请求的协议,是nginx的全局变量
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Remote-Port $remote_port;
...
}
在未信任时(即未激活trust proxy
时)我们node服务不会接受来路不明的数据,所以req.protocol
取出的值仍然是http
;
放上最终代码:
var protocolRedirect = function (req, res, next) {
const { headers, originalUrl } = req;
if (!isOnline || (isOnline && req.secure)) {
next();
} else {
res.redirect(301, `https://${headers.host}${originalUrl}`);
}
};
app.enable('trust proxy');
app.use(protocolRedirect);