
在flask应用中,当我们需要设置http响应头(例如设置cookie)时,不能仅仅依赖于直接返回一个json对象。flask的jsonify函数会创建一个response对象,其默认行为是返回json数据,但它不会自动包含之前在另一个response对象上设置的任何http头。
问题的核心在于,开发者创建了一个make_response对象并使用response.set_cookie()方法在其上设置了accessToken。然而,最终返回的却是jsonify(mensagem),这创建了一个全新的响应对象,而原先设置了cookie的response对象却被丢弃了,导致cookie信息未能随HTTP响应发送到客户端。
原始的错误代码示例:
# user.py (错误实现)
from flask import jsonify, make_response
import jwt # 假设已导入并配置SECRET_KEY
def loginAccount():
# ... 用户认证逻辑 ...
userId = str(list(db['users'].find({"email": email}))[0]['_id']) # 假设db和email已定义
tokenId = jwt.encode({'userId': userId}, SECRET_KEY, algorithm='HS256')
mensagem = {'message': f'Welcome to the CharTwo {email}!', 'tokenId': tokenId}
# 创建一个响应对象并设置cookie
response = make_response(jsonify(mensagem)) # 注意这里jsonify先被调用,创建了响应体
response.set_cookie('accessToken', tokenId)
# 错误:返回了一个新的jsonify结果,而不是包含cookie的response对象
return jsonify(mensagem)在上述代码中,response = make_response(jsonify(mensagem)) 这一行首先通过 jsonify(mensagem) 创建了一个响应体,然后 make_response 将其封装成一个可操作的 Response 对象。接着 response.set_cookie('accessToken', tokenId) 在这个 Response 对象上添加了 Set-Cookie 头。然而,随后的 return jsonify(mensagem) 却又创建了一个全新的、不包含之前设置的 Set-Cookie 头的 Response 对象并将其返回。这导致客户端接收到的响应中没有 accessToken 这个cookie。
要确保set_cookie()生效,必须返回那个经过set_cookie()操作的Response对象。
正确的loginAccount函数实现:
# user.py (正确实现)
from flask import jsonify, make_response
import jwt # 假设已导入并配置SECRET_KEY
def loginAccount():
# ... 用户认证逻辑 ...
# 假设db['users'].find({"email": email}) 成功找到用户
# 假设email和SECRET_KEY已在作用域内定义
userId = str(list(db['users'].find({"email": email}))[0]['_id'])
tokenId = jwt.encode({'userId': userId}, SECRET_KEY, algorithm='HS256')
mensagem = {'message': f'Welcome to the CharTwo {email}!', 'tokenId': tokenId}
# 首先创建包含JSON数据的响应对象
# make_response 可以接受字符串、字典、元组或Response对象作为参数
# 如果直接传入字典,Flask会将其自动转换为JSON响应
response = make_response(jsonify(mensagem))
# 在这个响应对象上设置cookie
response.set_cookie('accessToken', tokenId, httponly=True, secure=True, samesite='Lax') # 推荐添加httponly, secure, samesite等属性
# 返回包含cookie的响应对象
return response在这个修正后的版本中,response对象被正确创建并设置了cookie,最终也是这个response对象被返回。这样,Set-Cookie头就会包含在HTTP响应中,客户端浏览器就能接收并存储该cookie。
注意事项:
在前后端分离的架构中,尤其当前端(如VueJS)和后端(如Flask)部署在不同的域名或端口时,处理跨域请求是必不可少的。为了让客户端能够发送和接收带有凭证(如Cookie)的跨域请求,需要进行以下配置:
客户端(Axios)配置: 在发起请求时,必须设置withCredentials: true。这会指示浏览器在跨域请求中包含cookie和其他授权头。
const apiUrl = 'http://127.0.0.1:5000'
axios
.post(
`${apiUrl}/api/account/login`,
{
email: this.email,
password: this.password,
},
{
withCredentials: true, // 关键:允许发送和接收跨域凭证(包括cookie)
}
)
.then((response) => {
alert(response.data.message);
console.log(response);
})
.catch((error) => {
alert(`${error.response.data.erro}`);
console.log(error);
});服务器端(Flask-CORS)配置: Flask后端需要配置flask_cors扩展,以允许来自特定源的跨域请求携带凭证。
# main.py
from flask import Flask, make_response
from flask_cors import CORS, cross_origin
from user import loginAccount # 假设loginAccount已导入
app = Flask(__name__)
CORS(app, supports_credentials=True, origins=["http://localhost:8080", "http://127.0.0.1:8080"]) # 明确指定允许的源,并开启凭证支持
@app.route('/')
def principal():
return 'Welcome to the CharTwo API.'
@app.route('/api/account/login', methods=['POST'])
@cross_origin(supports_credentials=True) # 针对特定路由也开启凭证支持
def login_account():
return loginAccount()
if __name__ == '__main__':
app.run(debug=True)CORS(app, supports_credentials=True, origins=["http://localhost:8080"]):
@cross_origin(supports_credentials=True): 虽然在CORS(app, ...)中已经全局配置了supports_credentials=True,但在特定路由上再次使用@cross_origin装饰器并设置supports_credentials=True,可以进一步确保该路由的CORS行为符合预期,尤其是在更复杂的CORS策略中。
在Flask应用中正确设置HTTP Cookie的关键在于:
遵循这些原则,可以有效避免Flask中Cookie设置不生效的问题,并确保应用在安全和功能上都表现良好。
以上就是Flask set_cookie 失效问题解析与正确实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号