Angular SSR 中如何获取请求的原始来源
这段代码是一个用于获取请求来源 (origin) 的函数,在 Node.js 中使用 Express
框架来处理 HTTP 请求时特别有用。通过理解这段代码,可以深入了解如何处理代理请求头,以及如何确保生成的请求源 (origin) 是可信且正确的。
主要目的
这段代码的主要目的是获取当前请求的来源 (origin),即完整的协议和主机名 (protocol + hostname)。这个 origin
通常用在生成重定向链接、跨域资源共享 (CORS) 的情况下,确保正确地构建 URL。尤其在系统需要通过代理服务器 (reverse proxy) 处理请求时,函数需要获取正确的 host
信息以便使用。
这段代码结合了请求的协议 (req.protocol
)、HTTP 请求头中的 Host
和 X-Forwarded-Host
,来生成请求的 origin
。通过这种方式,能够确保函数获取到正确的主机地址,无论请求是通过直接访问,还是通过多个代理转发来的。
具体代码解释
trust proxy fn
const trustProxyFn = req.app.get('trust proxy fn');
trustProxyFn
是 Express 应用程序的一个内部函数,用于判断一个特定的请求是否来自受信任的代理服务器。req.app.get('trust proxy fn')
通过从 Express
应用实例中获取到当前的 trust proxy
配置。如果应用程序配置了 trust proxy
,那么这个函数将被用来判断传入请求的远程地址 (req.connection.remoteAddress
) 是否属于受信任的代理。
X-Forwarded-Host
的处理
let forwardedHost = req.get('X-Forwarded-Host');
X-Forwarded-Host
是一种常见的 HTTP 请求头,它通常被代理服务器添加,用来告诉最终的 Web 服务器,原始请求的主机 (host) 信息是什么。因为请求可能经过多个代理服务器转发,因此在某些应用场景中,必须获取到正确的 host
,这也是函数检查 X-Forwarded-Host
的原因。
判断受信任代理与多主机处理
if (forwardedHost && trustProxyFn(req.connection.remoteAddress, 0)) {
if (forwardedHost.indexOf(',') !== -1) {
forwardedHost = forwardedHost
.substring(0, forwardedHost.indexOf(','))
.trimRight();
}
return `${req.protocol}://${forwardedHost}`;
}
这里的逻辑是为了确保只有在请求是从可信任的代理服务器发来的时候,才会使用 X-Forwarded-Host
头的值。如果 trustProxyFn(req.connection.remoteAddress, 0)
返回 true
,表示该请求是来自于受信任的代理。
另外,如果 X-Forwarded-Host
中包含逗号,表明可能存在多个主机名,这是因为多个代理服务器可能会将其自己添加到请求头里。代码通过调用 .substring()
获取逗号前面的第一个主机名,使用 trimRight()
去除掉多余的空格,从而确保 forwardedHost
是一个单一的、有效的主机名。
返回请求的 origin
return `${req.protocol}://${forwardedHost}`;
代码在确认受信任代理的情况下返回 forwardedHost
,与请求的协议组合成完整的 origin
,例如 https://example.com
。
默认处理
else {
return `${req.protocol}://${req.get('host')}`;
}
如果没有找到 X-Forwarded-Host
,或者请求不是来自受信任的代理,那么返回默认的请求源信息,即使用请求的协议加上 Host
请求头中的内容,确保生成一个合理的 origin
。
举例说明
场景一:普通请求
假设你有一个正在运行的应用,它没有使用代理服务器。客户端直接向服务器发送请求。在这种情况下,req.get('X-Forwarded-Host')
将返回 undefined
,因为没有代理服务器插入该请求头。
假设请求使用的是 HTTPS
协议,并且主机名为 myapp.com
,则 req.protocol
为 https
,req.get('host')
为 myapp.com
。
那么函数 getRequestOrigin(req)
的返回结果将是:
https://myapp.com
场景二:通过代理请求
假设应用程序通过反向代理服务器部署,代理服务器在请求头中添加了 X-Forwarded-Host
。这个请求头通常表示最初的主机名。例如,客户端请求的 URL 为 https://client.com
,代理服务器将请求转发到你的应用,并且添加 X-Forwarded-Host: client.com
。
在这种情况下,假设应用配置了信任代理,且代理服务器的 IP 地址被列入受信任列表中:
req.get('X-Forwarded-Host')
的值为client.com
trustProxyFn(req.connection.remoteAddress, 0)
返回true
,表示代理服务器是可信的req.protocol
为https
函数返回结果将是:
https://client.com
场景三:多层代理的情况
在复杂的架构中,请求可能经过多个代理服务器转发,这时 X-Forwarded-Host
头部中可能包含多个值,以逗号分隔。例如,假设请求头为:
X-Forwarded-Host: proxy1.com, proxy2.com, client.com
在这种情况下,代码通过以下步骤处理:
- 使用
.indexOf(',')
找到第一个逗号的位置 - 使用
.substring(0, forwardedHost.indexOf(','))
提取出第一个主机名,即proxy1.com
- 使用
.trimRight()
去除可能存在的右侧空格
最后,函数返回的结果将是:
https://proxy1.com
场景四:没有信任代理配置
如果应用没有设置信任代理 (trust proxy
),或者请求不是从受信任的代理服务器发来的,即 trustProxyFn(req.connection.remoteAddress, 0)
返回 false
,即便存在 X-Forwarded-Host
头部,函数也不会使用这个值,而是默认采用 req.get('host')
。
假设:
req.protocol
为http
req.get('host')
为backend.com
那么返回结果为:
http://backend.com
安全性与可靠性考量
在这段代码中,安全性与可靠性是重要的考虑因素。
受信任的代理
trust proxy
是一个至关重要的安全配置。只有当请求来自受信任的代理时,代码才会使用 X-Forwarded-Host
的值。这是因为 X-Forwarded-Host
可以由任意客户端伪造,信任未验证的 X-Forwarded-Host
可能导致开放重定向漏洞,或其他类型的安全威胁。
多值处理
代码中考虑了 X-Forwarded-Host
可能存在多个值的情况。这在请求经过多个代理服务器时非常有用。多个值以逗号分隔,而代码确保只使用第一个值,这样可以更精确地反映原始请求的主机信息,避免混淆。
总结与注意事项
通过分析,我们可以看出这段代码的主要作用是从 HTTP 请求中准确提取出请求的 origin
,特别是考虑到代理服务器的存在情况。
trust proxy
的重要性:确保只信任来自受信任代理的X-Forwarded-Host
。- 处理多重代理:考虑到
X-Forwarded-Host
包含多个值的情况,通过提取第一个值来保证安全和准确性。 - 协议与主机的组合:结合协议和主机来生成正确的
origin
,确保返回结果可以用于跨域资源共享、安全重定向等功能。
在实际应用中,理解代理服务器的行为和正确处理代理请求头对于构建安全和可靠的后端系统至关重要。这段代码展示了如何在面对复杂的代理环境时有效管理请求源。
- 点赞
- 收藏
- 关注作者
评论(0)