英文:
FastAPI GET endpoint returns "405 method not allowed" response
问题
一个FastAPI中的`GET`端点返回正确的结果,但在使用`curl -I`时返回`405方法不允许`。这在所有的`GET`端点中都发生。因此,应用程序正在运行,但从负载均衡器对应用程序进行的健康检查失败。
有什么建议可能出了什么问题?
**代码**
@app.get('/health')
async def health():
"""
返回健康状态
"""
return JSONResponse({'status': 'ok'})
**结果**
curl http://172.xx.xx.xx:8080
[![][1]][1]
**返回头**
curl -I http://172.xx.xx.xx:8080
[![][2]][2]
英文:
A GET
endpoint in FastAPI is returning correct result, but returns 405 method not allowed
when curl -I
is used. This is happening with all the GET
endpoints. As a result, the application is working, but health check on application from a load balancer is failing.
Any suggestions what could be wrong?
code
@app.get('/health')
async def health():
"""
Returns health status
"""
return JSONResponse({'status': 'ok'})
result
curl http://172.xx.xx.xx:8080
return header
curl -I http://172.xx.xx.xx:8080
答案1
得分: 2
curl -I
选项(在您提供的示例中使用)与使用curl --head
相同,执行HTTP HEAD
请求,以获取仅headers(而不是资源的body/content):
> HTTP HEAD
方法请求在用HTTP GET
方法请求HEAD
请求的URL时将返回的headers。例如,如果URL可能产生大型下载,HEAD
请求可以读取其Content-Length
头以检查文件大小,而无需实际下载文件。
您正在尝试调用的请求资源/端点仅支持GET
请求;因此,会收到405 Method Not Allowed
响应状态代码,表示服务器知道请求方法,但目标资源不支持此方法。
为了演示这一点,看看下面的示例:
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
async def main():
return {'Hello': 'World'}
使用Python请求进行测试(使用curl -I http://127.0.0.1:8000
也可以获得类似的结果)
import requests
# 发送GET请求
# r = requests.get('http://127.0.0.1:8000')
# 发送HEAD请求
r = requests.head('http://127.0.0.1:8000')
# 检查响应的状态码
print(r.status_code, r.reason)
# 打印请求的headers
print(r.headers)
# 检查请求是否包含任何内容
print(r.content)
输出(由allow
响应头指示所请求资源支持哪些请求方法):
405 Method Not Allowed
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'allow': 'GET', 'content-length': '31', 'content-type': 'application/json'}
b''
相反,如果执行GET
请求(为了在上面的示例中发出GET
请求,请取消对GET
请求的注释并对HEAD
请求进行注释,或者在curl
中使用curl http://127.0.0.1:8000
),响应将如下所示:
200 OK
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'content-length': '17', 'content-type': 'application/json'}
b'{"Hello":"World"}'
解决方案
要使FastAPI端点支持多个HTTP请求方法(例如GET
和HEAD
请求),有以下解决方案。
解决方案1
为要支持的每个请求方法添加装饰器。例如:
from fastapi import FastAPI
app = FastAPI()
@app.head('/')
@app.get('/')
async def main():
return {'Hello': 'World'}
解决方案2
使用@app.api_route()
装饰器,该装饰器允许您定义端点支持的请求方法集。例如:
from fastapi import FastAPI
app = FastAPI()
@app.api_route('/', methods=['GET', 'HEAD'])
async def main():
return {'Hello': 'World'}
输出
上述两个解决方案在客户端发出HEAD
请求时都会如下响应:
200 OK
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'content-length': '17', 'content-type': 'application/json'}
b''
请注意,405 Method Not Allowed
响应也可能是其他原因引起的—请参阅此处和此处的相关答案,以及此处和此处。
英文:
The curl -I
option (which is used in the example you provided) is the same as using curl --head
and performrs an HTTP HEAD
request, in order to fetch the headers only (not the body/content of the resource):
> The HTTP HEAD
method requests the headers that would be
> returned if the HEAD
request's URL was instead requested with the
> HTTP GET
method. For example, if a URL might produce a large
> download, a HEAD
request could read its Content-Length
header
> to check the filesize without actually downloading the file.
The requested resource/endpoint you are trying to call supports only GET
requests; hence, the 405 Method Not Allowed
response status code, which indicates that the server knows the request method, but the target resource doesn't support this method.
To demonstrate this, have a look at the example below:
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
async def main():
return {'Hello': 'World'}
Test using Python requests (similar result is obtained using curl -I http://127.0.0.1:8000
)
import requests
# Making a GET request
# r = requests.get('http://127.0.0.1:8000')
# Making a HEAD request
r = requests.head('http://127.0.0.1:8000')
# check status code for response received
print(r.status_code, r.reason)
# print headers of request
print(r.headers)
# checking if request contains any content
print(r.content)
Output (indicating by the allow
response header which request methods are supported by the requested resource):
405 Method Not Allowed
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'allow': 'GET', 'content-length': '31', 'content-type': 'application/json'}
b''
If, instead, you performed a GET
request (in order to issue a GET
request in the example above, uncomment the line for GET
request and comment the one for HEAD
request, or in curl
use curl http://127.0.0.1:8000
), the response would be as follows:
200 OK
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'content-length': '17', 'content-type': 'application/json'}
b'{"Hello":"World"}'
Solutions
To make a FastAPI endpoint supporting more than one HTTP request methods (e.g., both GET
and HEAD
requests), the following solutions are available.
Solution 1
Add a decorator for each request method that you would like the endpoint to support. For instance:
from fastapi import FastAPI
app = FastAPI()
@app.head('/')
@app.get('/')
async def main():
return {'Hello': 'World'}
Solution 2
Use the @app.api_route()
decorator, which allows you to define the set of supported request methods for the endpoint. For example:
from fastapi import FastAPI
app = FastAPI()
@app.api_route('/', methods=['GET', 'HEAD'])
async def main():
return {'Hello': 'World'}
Output
Both solutions above would respond as follows (when a HEAD
request is issued by a client):
200 OK
{'date': 'Sun, 12 Mar 2023', 'server': 'uvicorn', 'content-length': '17', 'content-type': 'application/json'}
b''
Note that 405 Method Not Allowed
response may also be caused by other reasons—see related answers here and here, as well as here and here.
答案2
得分: 1
FastAPI存在一个问题。 它允许在该路径上使用GET
方法,而不是HEAD
方法。
curl -I
选项等同于--head
。它发送一个HTTP HEAD
请求。
由于FastAPI服务器不支持HEAD方法,仅支持GET,因此它正确地响应HTTP-405。
有一个解决方法 - 添加手动定义的@app.head()
。
英文:
FastAPI has a bug. It allows a GET
method on that path, not a HEAD
method.
The curl -I
option is equivalent to the --head
. It sends an HTTP HEAD
request.
Because the FastAPI server does not support the HEAD method, only the GET it correctly responds with a HTTP-405.
There is a workaround - to add manually defined @app.head()
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论