您的位置:

RuntimeError("This decorator can only be used at local scopes ""when a request context is on the stack. For instance within ""view functions.")的处理方案

  发布时间:2023-02-22 14:57:13
在 Flask 中,这通常是在视图函数或请求钩子中进行的。使用test_client() 也是类似的道理当然,还有另一种方法来解决这个问题,即使用 Flask 提供的 `app.route` 方法将路由添加到应用程序中,而不是使用装饰器。总结一下,这个错误是因为在请求上下文不存在的地方使用了视图函数外的路由装饰器,可以使用或 app.test_client() 创建模拟请求上下文或 使用app.route() 方法来解决这个问题。

报错的原因

这个错误是因为在请求上下文不存在的情况下使用了试图函数之外的装饰器。在 Flask 中,一些装饰器(如 `@app.route` 和 `@app.before_request`)只能在请求上下文存在时使用,因此它们只能用于视图函数或请求钩子等。如果在请求上下文不存在的位置使用这些装饰器,就会产生这个错误。

如何解决

解决这个错误的方法是确保在使用这些装饰器时请求上下文存在。在 Flask 中,这通常是在视图函数或请求钩子中进行的。

如果您确实需要在请求上下文不存在的位置使用这些装饰器,则可以考虑使用 `app.test_request_context()` 或 `app.test_client()` 创建模拟请求上下文,然后在其中使用装饰器。

例如:


with app.test_request_context():
    @app.route('/')
    def index():
        return 'Hello, World!'

或者


client = app.test_client()
with app.test_request_context():
    @app.route('/')
    def index():
        return 'Hello, World!'
    client.get('/')

这样虽然装饰器不在视图函数中,但是由于创建了模拟请求上下文,所以装饰器仍能正常工作。

使用例子

当然,下面是一个使用 `app.test_request_context()` 创建模拟请求上下文的示例:


from flask import Flask, jsonify

app = Flask(__name__)

def check_auth(username, password):
    return username == 'admin' and password == 'secret'

def authenticate():
    message = {'message': "Authenticate."}
    resp = jsonify(message)
    resp.status_code = 401
    resp.headers['WWW-Authenticate'] = 'Basic realm="Example"'
    return resp

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

@app.route('/secret-page')
@requires_auth
def secret_page():
    return "Welcome to the secret page!"

with app.test_request_context(headers={'Authorization': 'Basic YWRtaW46c2VjcmV0'}):
    # YWRtaW46c2VjcmV0 is a base64 encoded string for 'admin:secret'
    @app.route('/admin-page')
    @requires_auth
    def admin_page():
        return "Welcome to the admin page!"

此示例中,我们定义了一个名为 `requires_auth` 的装饰器,用于验证请求的授权头。我们使用 `app.test_request_context(headers={'Authorization': 'Basic YWRtaW46c2VjcmV0'})` 创建了一个模拟请求上下文,并在其中使用了 `@app.route('/admin-page')` 装饰器,而不是在视图函数中使用它。

这样就可以在请求上下文不存在的地方使用装饰器,而不会出现"This decorator can only be used at local scopes" 这样的错误。

使用test_client() 也是类似的道理


client = app.test_client()
with app.test_request_context(headers={'Authorization': 'Basic YWRtaW46c2VjcmV0'}):
    @app.route('/admin-page')
    @requires_auth
    def admin_page():
        return "Welcome to the admin page!"
    client.get('/admin-page')

当然,还有另一种方法来解决这个问题,即使用 Flask 提供的 `app.route` 方法将路由添加到应用程序中,而不是使用装饰器。

例如:


def secret_page():
    return "Welcome to the secret page!"
app.route('/secret-page', methods=['GET'])(secret_page)

这里我们用app.route() 方法来代替 @app.route 装饰器,并将 secret_page 函数作为参数传递给它,这样就可以在请求上下文不存在的地方定义路由,而不会出现"This decorator can only be used at local scopes" 这样的错误。

总结一下,这个错误是因为在请求上下文不存在的地方使用了视图函数外的路由装饰器,可以使用 app.test_request_context() 或 app.test_client() 创建模拟请求上下文或 使用app.route() 方法来解决这个问题。