FastAPI的GET端点返回”405方法不允许”响应。

huangapple go评论107阅读模式
英文:

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

FastAPI的GET端点返回”405方法不允许”响应。

return header

curl -I http://172.xx.xx.xx:8080

FastAPI的GET端点返回”405方法不允许”响应。

答案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请求方法(例如GETHEAD请求),有以下解决方案。

解决方案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().

huangapple
  • 本文由 发表于 2023年3月12日 15:55:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75711757.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定