Django视图中asyncio调用失效,Pyppeteer导出PDF遇RuntimeError
解决Pyppeteer导出PDF时触发的RuntimeError问题
嘿,我帮你捋清楚这个问题:你遇到的RuntimeError,大概率是因为在已经有活跃事件循环的线程中,又尝试用asyncio.get_event_loop().run_until_complete()启动新的事件循环导致的冲突——毕竟像Flask、Django这类Web框架的视图函数,本身可能已经运行在一个事件循环上下文里了,重复操作自然会报错。
下面给你两种针对性的解决方案,你可以根据自己的视图类型来选:
方案一:如果是异步视图(优先推荐)
如果你的Web框架支持异步视图(比如FastAPI、Django 3.1及以上版本),完全不用手动折腾事件循环,直接await你的export_pdf函数就行:
# 举个FastAPI异步视图的例子 from fastapi import FastAPI, Request, Response from pyppeteer import launch app = FastAPI() async def export_pdf(url): browser = await launch() page = await browser.newPage() await page.goto(url) pdf = await page.pdf({'printBackground': True}) await browser.close() return pdf @app.get("/export-pdf") async def pdf_export_endpoint(request: Request): # 生成目标页面的完整绝对URL target_url = request.url_for("your_target_page_endpoint") pdf_content = await export_pdf(str(target_url)) return Response(content=pdf_content, media_type="application/pdf")
如果是Django的异步视图,写法类似:
async def pdf_export_view(request): full_url = request.build_absolute_uri() pdf_content = await export_pdf(full_url) response = HttpResponse(pdf_content, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="export.pdf"' return response
方案二:如果必须在同步视图中调用
如果你的视图是同步的,那就需要用嵌套事件循环来解决冲突,这里可以借助nest_asyncio库:
- 先安装这个库:
pip install nest_asyncio
- 修改你的代码逻辑:
import nest_asyncio import asyncio from pyppeteer import launch from django.http import HttpResponse # 注意:把这行放在项目初始化的地方(比如Django的settings.py、Flask的启动文件),只需要执行一次 nest_asyncio.apply() async def export_pdf(url): browser = await launch() page = await browser.newPage() await page.goto(url) pdf = await page.pdf({'printBackground': True}) await browser.close() return pdf # 同步视图中的调用方式 def sync_pdf_view(request): # 这里一定要用完整的绝对URL,相对路径会导致Pyppeteer导航失败 full_url = request.build_absolute_uri() # 现在可以安全运行异步函数了 pdf_content = asyncio.get_event_loop().run_until_complete(export_pdf(full_url)) response = HttpResponse(pdf_content, content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="export.pdf"' return response
额外提醒
你之前用self.request.get_full_path()获取的是相对路径,Pyppeteer的page.goto()需要完整的绝对URL(比如http://localhost:8000/your-page),否则会导航失败,建议改成request.build_absolute_uri()来生成正确的URL哦。
内容的提问来源于stack exchange,提问作者Bestasttung
相关产品推荐
相关产品推荐

