我将 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?
我以前也遇到过这个问题。一种可能的解决方案是创建一个自定义
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
。
我也有同样的问题。在开发环境中所有链接都是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
毕竟只需在主文件中导入此类并初始化管理类
当您只想在需要时替换 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