Flask中如何立即返回200 Ok响应以解决Payfast ITN的307临时重定向问题
我之前集成Payfast的时候也碰到过一模一样的问题——用户支付成功了,但ITN回调总是返回307,试了好几种返回200的写法都没用,折腾了好一阵才找到根源。结合你的情况,我给你梳理几个排查方向和解决方案:
先确认核心前提:你的路由真的接收到请求了吗?
你在代码里加了日志,先去看日志里有没有Request received:的记录。如果完全没看到,说明请求根本没走到这个路由,大概率是下面两个问题:
- Payfast配置的回调URL和你的路由不匹配(比如多了/少了斜杠,或者域名不对)
- 你的服务器(Nginx/Apache)配置了自动重定向规则,比如把无斜杠的URL重定向到带斜杠的版本,哪怕你加了
strict_slashes=False也可能被服务器层面的规则覆盖
如果日志有记录,那问题出在响应返回的环节,往下看:
解决方案1:先返回200响应,再异步处理ITN逻辑
Payfast的ITN机制要求你立即返回200 OK,不能因为处理验证逻辑而阻塞响应。PHP示例里的flush()就是为了确保响应立刻发送,放到Flask里,你需要先返回响应,再把ITN的验证/处理逻辑放到后台线程里:
from flask import Response, request import threading @orders.route('/status/notify', methods=['POST'], strict_slashes=False) def notify(): # 先构造并返回200响应,设置Connection: close确保连接立刻断开 response = Response('OK', status=200, mimetype='text/plain') response.headers['Connection'] = 'close' # 把ITN处理逻辑放到后台线程,避免阻塞响应返回 def process_itn(): pf_data = request.form.to_dict() # 这里写你的Payfast签名验证、订单状态更新等逻辑 current_app.logger.debug(f"Received ITN data: {pf_data}") threading.Thread(target=process_itn, daemon=True).start() return response
注意:ITN一般都是POST请求,不需要开GET方法,反而可能增加安全风险,所以路由里只保留methods=['POST']就好。
解决方案2:排查全局钩子/中间件的干扰
如果你的Flask应用有全局的before_request或者after_request钩子(比如登录验证、权限检查),这些钩子可能会对这个路由做重定向处理。你需要把这个路由排除在外:
@app.before_request def before_request(): # 跳过ITN回调路由的全局钩子处理 if request.path == '/status/notify': return None # 其他全局逻辑,比如登录验证...
解决方案3:检查服务器反向代理配置
如果你用Nginx或Apache做反向代理,一定要确保配置里没有自动添加斜杠或重定向的规则。比如Nginx的try_files指令如果配置不当,会把无斜杠的URL重定向到带斜杠的版本,哪怕Flask设置了strict_slashes=False也没用。举个Nginx的正确配置示例:
location /status/notify { proxy_pass http://your-flask-app:5000/status/notify; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
不要用location /这种泛匹配的规则来处理这个路由,单独配置更稳妥。
最后用curl测试路由
你可以自己用curl模拟Payfast的请求,看看本地返回的状态码是不是200:
curl -X POST http://your-domain.com/status/notify -d "test=123" -v
如果curl返回的是200,但Payfast那边还是307,那可能是Payfast侧的问题,比如他们的请求链路里有代理导致重定向,这时候可以联系Payfast的技术支持确认。
备注:内容来源于stack exchange,提问作者JBstrap




