Jinja2 模板中 url_for 创建的 FastAPI 链接使用 HTTP 而不是 HTTPS

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

我将 Flask 中由 waitress 提供的应用程序迁移到由 uvicorn 提供的 FastAPI,但我无法强制链接(由 index.html 模板内的 url_for 生成)使用 HTTPS 而不是 HTTP。

我和女服务员一起使用:

from waitress import serve
import flask_app

PORT=5000
HOST_IP_ADDRESS='0.0.0.0'

serve(flask_app.app, host=HOST_IP_ADDRESS, port=PORT, url_scheme="https")

对于 uvicorn,我尝试使用 proxy_headers,但这不起作用。我在index.html中使用了解决方法

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

它正确地从静态文件加载了 style.css,但到另一个端点的链接仍然使用 HTTP。

有没有一种简单的方法可以强制 url_for 创建的所有链接都使用 HTTPS?

https jinja2 fastapi uvicorn
3个回答
5
投票

我以前也遇到过这个问题。一种可能的解决方案是创建一个自定义

url_for
函数来更改协议,然后将其添加到 Jinja 环境中。一种可能的实现可能如下所示:

template = Jinja2Templates("/path/to/templates")

def https_url_for(request: Request, name: str, **path_params: Any) -> str:

    http_url = request.url_for(name, **path_params)

    # Replace 'http' with 'https'
    return http_url.replace("http", "https", 1)

template.env.globals["https_url_for"] = https_url_for

您必须将请求传递给函数,以便它知道如何生成

url_for
,但无论怎样,请求都应该传递到您的 Jinja2 模板。

然后您可以在 Jinja2 模板中使用它,如下所示:

https_url_for(request, "/https/path", search="hi")

生成的网址应类似于

https://<domain>/https/path?search=hi


0
投票

我也有同样的问题。在开发环境中所有链接都是http。 我就是这样解决的。

from starlette.templating import Jinja2Templates
from sqladmin import Admin
from jinja2 import ChoiceLoader, FileSystemLoader, PackageLoader
import jinja2
if hasattr(jinja2, "pass_context"):
    pass_context = jinja2.pass_context
else:
    pass_context = jinja2.contextfunction


@pass_context
def https_url_for(context: dict, name: str, **path_params) -> str:
    request = context["request"]
    http_url = request.url_for(name, **path_params)
    return http_url.replace("http", "https", 1)


class CustomAdmin(Admin):
    def init_templating_engine(self) -> Jinja2Templates:
        templates = Jinja2Templates("templates")
        loaders = [
            FileSystemLoader(self.templates_dir),
            PackageLoader("sqladmin", "templates"),
        ]

        templates.env.loader = ChoiceLoader(loaders)
        templates.env.globals["min"] = min
        templates.env.globals["zip"] = zip
        templates.env.globals["admin"] = self
        templates.env.globals["is_list"] = lambda x: isinstance(x, list)
        templates.env.globals["url_for"] = https_url_for
        return templates

毕竟只需在主文件中导入此类并初始化管理类


0
投票

当您只想在需要时替换 url 架构时(在示例中,“x-forwarded-proto”标头由反向代理设置)

from fastapi import Request    
from fastapi.templating import Jinja2Templates
from jinja2 import pass_context


@pass_context
def urlx_for(context: dict, name: str, **path_params: Any, ) -> str:
    request: Request = context['request']
    http_url = request.url_for(name, **path_params)
    if scheme := request.headers.get('x-forwarded-proto'):
        return http_url.replace(scheme=scheme)
    return http_url


templates = Jinja2Templates(directory="core/templates")
templates.env.globals['url_for'] = urlx_for

我们需要使用

@pass_context
装饰器让jinja2将上下文作为第一个参数发送,否则我们需要传递请求

解决方案适用于 Jinja2>=3.0.0

© www.soinside.com 2019 - 2024. All rights reserved.