如何实现Flask异步POST响应且不阻塞整个服务?
解决Flask异步应用被外部请求阻塞的问题
你的问题核心在于同步阻塞的requests库:虽然把视图函数定义成了async,但requests.post()是完全同步的调用,执行到这一行时会直接卡住整个事件循环,导致其他请求只能排队等待,根本发挥不了异步Flask的并发能力。
下面给两种实用的解决办法:
方法一:使用异步HTTP库(推荐)
用aiohttp替代requests,它是原生异步的HTTP客户端,能让事件循环在等待外部响应时,转而处理其他进来的请求。
- 先安装aiohttp:
pip install aiohttp
- 修改后的代码:
import aiohttp from flask import Flask app = Flask(__name__) @app.route('/service', methods=['GET', 'POST']) async def service(): url = "你的外部服务器地址" try: # 用异步会话发送请求 async with aiohttp.ClientSession() as session: async with session.post(url) as response: # 根据实际需求获取响应,比如text()或json() get_data = await response.text() except aiohttp.ClientConnectionError: print('请求无响应') # 这里可以添加返回给客户端的响应内容 return "处理完成"
方法二:把同步请求放到线程池执行(兼容老代码)
如果一定要保留requests,可以用asyncio.run_in_executor把同步请求放到线程池里运行,避免阻塞主事件循环:
import requests import asyncio from flask import Flask app = Flask(__name__) @app.route('/service', methods=['GET', 'POST']) async def service(): url = "你的外部服务器地址" try: # 用线程池执行同步的post请求 get_data = await asyncio.get_event_loop().run_in_executor( None, requests.post, url ) # 如果需要传递请求参数,用lambda包装: # get_data = await asyncio.get_event_loop().run_in_executor( # None, # lambda: requests.post(url, data={"key": "value"}, headers={"X-Token": "xxx"}) # ) except requests.ConnectionError: print('请求无响应') return "处理完成"
总结
- 优先选方法一,
aiohttp的异步逻辑更契合Flask异步模式,性能损耗更低; - 方法二是折中方案,适合不想替换现有
requests代码的场景,但线程切换会有少量额外开销。
内容的提问来源于stack exchange,提问作者Nicolas-Fractal
相关产品推荐
相关产品推荐

