Haj*_*zip 1 cors preflight docker traefik fastapi
我有一个非常简单的 FastAPI-Traefik-Docker 设置,您可以在这里找到: https: //github.com/mshajarrazip/fastapi-traefik-docker-cors
\n只需docker-compose up -d运行 FastAPI 和 traefik 服务即可。
此设置中未配置 TLS/SSL。
\n该应用程序有两个端点 GET“/hello”和 POST“/add”,它们除了返回 json 响应之外什么也不做:
\n在app/main.py
import logging\n\nfrom app import routes\nfrom fastapi import FastAPI\nfrom fastapi.middleware.cors import CORSMiddleware\n\ndef create_application() -> FastAPI:\n app = FastAPI(title="\xe2\x9c\xa8 ML API \xe2\x9c\xa8")\n\n app.include_router(routes.hello.router)\n\n # add CORS\n # origins = ["*"]\n app.add_middleware(\n CORSMiddleware,\n allow_origins=["*"], # Allows all origins\n allow_credentials=True,\n allow_methods=["*"], # Allows all methods\n allow_headers=["*"], # Allows all headers\n )\n\n return app\n\n\napp = create_application()\nRun Code Online (Sandbox Code Playgroud)\n在app/routes/...
from fastapi import APIRouter\n\nrouter = APIRouter()\n\n@router.get("/hello")\ndef hello():\n return {\n "message": "Hello!"\n }\n\n@router.post("/add")\ndef add_to_db():\n return {\n "id": 1, \n "name": "Salmah",\n "age": 29\n }\nRun Code Online (Sandbox Code Playgroud)\n通过curl 和Postman 调用这些端点是有效的:
\ncurl -X \'GET\' http://172.16.239.132:81/hello -H \'Host: basic.api\'\ncurl -X \'POST\' http://172.16.239.132:81/add -H \'Host: basic.api\'\nRun Code Online (Sandbox Code Playgroud)\n但不是从 Chrome 浏览器上运行的简单 html 文件中的简单 javascript 获取(从我的本地计算机到运行 traefik 的远程服务器):
\n<html>\n <Button id="btnAddData" onclick="AddData();"> Add Data </Button>\n</html>\n\n<script>\nvar myHeaders = new Headers();\nmyHeaders.append("Content-Type", "application/json");\nmyHeaders.append("Host", "basic.api");\n\nvar requestOptions = {\n method: \'POST\',\n headers: myHeaders,\n redirect: \'follow\'\n};\n\nfunction AddData(){\n console.log("click");\n\n fetch("http://172.16.239.132:81/add", requestOptions)\n .then(response => response.text())\n .then(result => console.log(result))\n .catch(error => console.log(\'error\', error));\n}\n</script>\nRun Code Online (Sandbox Code Playgroud)\n回复:
\nAccess to fetch at \'http://172.16.239.132:81/add\' from origin \'null\' has been blocked by CORS policy: Response to preflight request doesn\'t pass access control check: No \'Access-Control-Allow-Origin\' header is present on the requested resource. If an opaque response serves your needs, set the request\'s mode to \'no-cors\' to fetch the resource with CORS disabled.\nRun Code Online (Sandbox Code Playgroud)\ntraefik 通过以下方式记录docker-compose logs -f reverse-proxy:
reverse-proxy_1 | 10.32.26.13 - - [18/Dec/2022:03:34:45 +0000] "OPTIONS /add HTTP/1.1" 404 19 "-" "-" 9 "-" "-" 0ms\nRun Code Online (Sandbox Code Playgroud)\n我认为问题可能是因为我正在从本地文件系统运行 fetch,所以我使用curl 模拟 OPTIONS 请求(这是请求 GET):
\ncurl -i -X OPTIONS \\\n -H \'Access-Control-Request-Method: GET\' \\\n -H \'Access-Control-Request-Headers: Content-Type\' \\\n -H \'Host: basic.api\' \\\n "http://172.16.239.132:81/hello"\nRun Code Online (Sandbox Code Playgroud)\n我收到 405 Method not allowed 错误:
\nHTTP/1.1 405 Method Not Allowed\nAllow: GET\nContent-Length: 31\nContent-Type: application/json\nDate: Sun, 18 Dec 2022 03:39:40 GMT\nServer: uvicorn\n\n{"detail":"Method Not Allowed"}\nRun Code Online (Sandbox Code Playgroud)\n当我设置时也是如此\'Access-Control-Request-Method: OPTIONS\'。
这是我在 docker-compose.yml 中的 traefik 设置:
\nservices:\n reverse-proxy:\n image: traefik:v2.9\n ports:\n - ${API_PORT}:80\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - ./traefik.yml:/etc/traefik/traefik.yml\n labels:\n - "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"\n - "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"\n - "traefik.http.middlewares.cors.headers.accesscontrolmaxage=100"\n - "traefik.http.middlewares.cors.headers.addvaryheader=true"\nRun Code Online (Sandbox Code Playgroud)\n我遵循了关于CORS headers 的官方 Traefik 文档的建议,这显然不是我需要知道的全部内容。
\n我不是 CORS/网络专家,因此这增加了我当前的困难:(我不知道如何解决这个问题。我已经用各种解决方案组合研究了五天。在首先,我怀疑 FastAPI 的 CORSMiddleware 模块有问题 - 但 FastAPI 代码中设置的 CORSMiddleware 正在工作,因为我在没有 traefik 的情况下对其进行了测试,并且工作正常。
\n我确信这是 traefik 新手中的一个常见问题,但在我用谷歌搜索的所有地方,我都找不到简单的答案(或者也许答案已经存在,我只是不明白)。另外,他们的所有设置并不像我当前的设置那么简单(他们配置了 TLS/SSL 等一切)。
\n我认为问题不在于 FastAPI,而在于 traefik 本身。当通过 fetch 调用端点时,我认为请求甚至不会到达 FastAPI 应用程序。因此,任何解决方案都应该适用于 traefik 反向代理,因此,应该适用于任何其他部署,无论它是否是 FastAPI。
\n请帮助:(我相信它也会帮助很多初学者。
\n要在 docker-compose.yml 文件中为后端服务启用 CORS,您可以向后端服务添加以下标签:
# Enable CORS headers
- "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"
- "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
- "traefik.http.middlewares.cors.headers.accesscontrolmaxage=100"
- "traefik.http.middlewares.cors.headers.addvaryheader=true"
Run Code Online (Sandbox Code Playgroud)
这些标签将配置 CORS 中间件以允许任何 HTTP 方法、任何来源以及 CORS 标头的最长期限为 100 秒。addvaryheader 标志还将向响应添加 Vary 标头,以指示响应可能会根据 Origin 标头而有所不同。
将这些标签添加到后端服务后,您可以通过将中间件添加到路由器的中间件标签来将 CORS 中间件应用到路由器。例如:
# Use the CORS middleware for the app-https router
- traefik.http.routers.app-https.middlewares=cors
Run Code Online (Sandbox Code Playgroud)
这会将 CORS 中间件应用于 app-https 路由器,允许后端服务接受来自指定来源的 CORS 请求。就我而言,它是 https。然而; 我认为你应该为 http 添加这个
- traefik.http.routers.my-router.middlewares=cors
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7103 次 |
| 最近记录: |