简体   繁体   中英

Flask generic exception handler unable to catch 405 error

I've created an exception handler according to this piece of documentation :

import json

from flask import Blueprint, abort, current_app, jsonify, make_response, request
from werkzeug.exceptions import HTTPException

import pmo.service as pmo

ops = Blueprint("ops", __name__)


@ops.route("/today", methods=["GET"])
def get_today():
    current_app.logger.info("Getting an entry for 'today'")
    try:
        return jsonify(pmo.get_today_entry())
    except IndexError:
        abort(404, "No entry for today")


@ops.errorhandler(Exception)
def handle_exception(e):
    # pass through HTTP errors as json
    if isinstance(e, HTTPException):
        response = e.get_response()
        payload = json.dumps({
            "code": e.code,
            "name": e.name,
            "description": e.description,
        })
        response.data = f"{payload}\n"
        response.content_type = "application/json"
        return make_response(response, e.code)

    # now handle non-HTTP exceptions only
    response_body = {"code": 500, "message": "unhandled exception occurred", "details": str(e)}
    return make_response(response_body, 500)

I decided to use this approach because I'm developing a REST api and wanted to get rid of any html responses. Still when I issue a POST request in order to trigger a 405 error it is being returned as html document and not json:

❯ curl -X POST localhost:5000/today

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

While GET request is handled as expected:

❯ curl localhost:5000/today

{"code": 404, "name": "Not Found", "description": "No entry for a given day"}

In fact the error handler is not being invoked on 405, I've verified that with a debugger.

What am I doing wrong?

Your error handler needs to be on the app object, not the blueprint. Try:

@app.errorhandler(Exception)
def handle_exception(e):
    ...

Other than that, I don't see anything problematic about your code.

As @KenKinder kindly pointed out in the comment the problem was in the placement of the generic exception handler. After moving it to application's entrypoint it started to work like a charm.

Already answered, it needs to go on the @app but some further details:

In Modular Applications with Blueprints, most error handlers will work as expected. However, there is a caveat concerning handlers for 404 and 405 exceptions.

This is because the blueprint does not “own” a certain URL space, so the application instance has no way of knowing which blueprint error handler it should run if given an invalid URL.

Documentation for this: https://flask.palletsprojects.com/en/2.2.x/errorhandling/#blueprint-error-handlers

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM