如何在FastAPI中获取原始URL?

问题描述 投票:0回答:2

是否可以在 FastAPI 中获取请求来自的 URL?

例如,如果我有一个在

api.mysite.com/endpoint
请求的端点,并且从
www.othersite.com
向该端点发出请求,有没有一种方法可以在我的端点函数中检索字符串“www.othersite.com”

python http httprequest fastapi http-referer
2个回答
4
投票

问题的前提,可以表述为

服务器可以识别请求来自的 URL

被误导了。确实,某些 HTTP 请求(尤其是浏览器发出的某些请求)带有

Origin
标头 和/或
Referer
[原文如此] 标头
。此外,
Forwarded
标头
(如果存在)包含有关发出请求的位置的信息。然而,HTTP 规范中没有任何内容要求一般的请求通告它们来自哪里。

因此,无论是使用 FastAPI 还是其他一些服务器技术,都无法确定请求来自何处。


0
投票

更新

如@jub0bs 所述,HTTP 请求通常带有

Referer
标头,其中包含请求资源的地址。根据MDN的文档

Referer
HTTP 请求头包含绝对或部分 请求资源的地址。
Referer
标题 允许服务器 identify referring pages 人们是 来自或正在使用请求资源的地方访问。这个数据 可用于分析、日志记录、优化缓存等。

当您单击链接时,

Referer
包含页面的地址 包括链接。当你向另一个人发出资源请求时 域,
Referer
包含使用该页面的地址 请求资源.

在 FastAPI 中,您可以检索请求标头,如此处所示。因此,您可以通过以下方式获取

Referer
URL:

from fastapi import FastAPI, Request

app = FastAPI()

@app.get('/')
def main(request: Request):
    referer = request.headers.get('referer')
    return referer

原答案

根据 FastAPI 文档,因此 Starlette 的

假设您想获取客户端的 IP 地址/主机 你的路径操作函数。

@app.get("/items/{item_id}")
def read_root(item_id: str, request: Request):
    client_host = request.client.host
    return {"client_host": client_host, "item_id": item_id}

请注意,如果您在反向代理服务器(如 nginx)后面运行,您需要运行带有

--proxy-headers
标志的 Uvicorn 以接受此类标头(默认情况下已启用,但仅限于仅信任连接 IP)在
forwarded-allow-ips
配置中),以及带有
--forwarded-allow-ips='*'
标志以确保域套接字被信任为代理标头的源(而不是使用
'*'
通配符信任来自所有 IP 的标头,它将是更安全地信任来自反向代理服务器 IP 的only 代理标头)。根据 Uvicorn 的文档

  • --proxy-headers / --no-proxy-headers
    - 启用/禁用
    X-Forwarded-Proto
    X-Forwarded-For
    X-Forwarded-Port
    以填充远程地址信息。默认为enabled,但仅限于only信任
    forwarded-allow-ips
    配置中的连接IP。

  • --forwarded-allow-ips
    - 逗号分隔的 IP 列表以信任代理标头。默认为
    $FORWARDED_ALLOW_IPS
    环境变量(如果可用)或
    '127.0.0.1'
    。通配符
    '*'
    表示 always trust.

为确保代理转发它们,您应该确保代理设置了

X-Forwarded-For
X-Forwarded-Proto
标头(请参阅Uvicorn的文档,以及这篇文章以获取更多详细信息)。

假设对您的 API 的请求是在您尝试检索其 URL/域的网站的后端处理的,而不是允许用户直接从他们的前端向您的 API 发出请求——因此,在这种情况下,客户端的IP地址将是网站的(服务器/后端)IP地址,而不是浏览网站的用户的IP地址——一旦你获得网站的IP地址(使用request.client.host

,如前所述),你可以执行反向 DNS 查找以获取网站的主机名(虽然并不总是存在,或者没有有意义的名称),如下例所示。从那里,您可以在线查找有关主机名或 IP 地址本身的信息。您还可以创建一个数据库,其中包含您解析的每个 IP 地址(或更好的主机名)以供将来参考。

import socket #address = '2001:4860:4860::8888' # Google's Public DNS IPv6 address address = '216.58.214.14' # a Google's IP address print(socket.gethostbyaddr(address)[0])
    
© www.soinside.com 2019 - 2024. All rights reserved.