我运行具有 HTTP 和 HTTPS 端点的 Azure 云服务(使用 Node.js)。诀窍是让 IIS 为您处理 SSL 终止,以便您的 Node.js 应用程序仅侦听 HTTP(使用 process.env.PORT)。
我已将证书上传到 Windows Azure 门户,然后我的 ServiceDefinition.csdef 文件如下所示:
<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="my-cloud-service-name" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="my-cloud-service-name" vmsize="Small">
<Imports />
<Startup>
<Task commandLine="setup_web.cmd > log.txt" executionContext="elevated">
<Environment>
<Variable name="EMULATED">
<RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
<Variable name="RUNTIMEID" value="node;iisnode" />
<Variable name="RUNTIMEURL" value="http://az413943.vo.msecnd.net/node/0.8.4.exe;http://az413943.vo.msecnd.net/iisnode/0.1.21.exe" />
</Environment>
</Task>
<Task commandLine="node.cmd ..\startup.js" executionContext="elevated" />
</Startup>
<Endpoints>
<InputEndpoint name="Web" protocol="http" port="80" />
<InputEndpoint name="WebSSL" protocol="https" port="443" certificate="my-certificate-name" />
</Endpoints>
<Certificates>
<Certificate name="my-certificate-name" storeLocation="LocalMachine" storeName="CA" />
</Certificates>
<Sites>
<Site name="Web">
<Bindings>
<Binding name="Web" endpointName="Web" />
<Binding name="WebSSL" endpointName="WebSSL" />
</Bindings>
</Site>
</Sites>
</WebRole>
</ServiceDefinition>
然后在我的 Web.cloud.config 文件的 iisnode 元素中,我确保提升 HTTPS 服务器变量:
<iisnode debuggingEnabled="false" devErrorsEnabled="false" loggingEnabled="false" node_env="production" promoteServerVars="HTTPS" />
这让我可以使用一些 Express.js 中间件设置 x-forwarded-proto 标头,该中间件是识别 HTTP 请求的原始协议的事实标准:http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
exports.xForwardedProto = function(req, res, next) {
if(!req.headers['x-forwarded-proto']) {
if(req.headers['x-arr-ssl'] || req.headers['x-iisnode-https'] === 'on') {
req.headers['x-forwarded-proto'] = 'https';
}
}
next();
};
然后,当我想将 HTTP 请求重定向到 HTTPS 时,我会使用 Express.js 中间件:
exports.httpsOnly = function(req, res, next) {
if(req.protocol === 'http' && process.env.NODE_ENV && process.env.NODE_ENV != 'development') {
return res.redirect(301, 'https://' + req.get('host') + req.url);
}
next();
};