Django开发中如何捕获调用YouTube API时触发的各类异常
异常捕获失效的核心原因
你当前的捕获逻辑抓不到报错,基本逃不出这几个情况:
- 捕获范围太窄:只拦截了某一类特定异常(比如仅捕获了requests库的网络错误),但Google官方YouTube API客户端抛出的自定义异常、数据解析异常、参数校验异常都没覆盖
- 作用域不对:如果「Error 1」位置的代码跑在Celery异步任务、子线程里,写在主线程/调用方外层的try-except根本无法捕获子执行流抛出的异常
- 异常类未正确导入:
google-api-python-client抛出的HTTP错误属于googleapiclient.errors下的自定义类型,没提前导入的话无法精准捕获 - 漏处理跨模块异常:比如网络超时触发的
TimeoutError、API配额耗尽返回的403、参数非法返回的400、私有视频触发的404等异常散落在不同模块,窄范围捕获必然漏判
可直接落地的实现方案
第一步:先枚举全量异常类型
先临时加全量捕获,跑一遍所有会触发报错的场景,把所有出现的异常类型摸清楚,避免漏判:
import traceback try: # 这里放「Error 1」位置对应的完整业务代码:初始化API客户端、构造请求、拉取视频、解析响应的全流程 pass except BaseException as e: # 以下为临时调试代码,上线前删除 print(f"异常类型:{type(e).__name__},异常详情:{str(e)}") print(traceback.format_exc()) raise
注意:
BaseException仅用于临时调试抓全量异常,正式代码禁止直接用它做兜底拦截,否则会把键盘中断、进程退出这类系统级异常拦住,导致服务假死。
第二步:分层精准捕获异常,返回自定义提示
先导入所有需要用到的异常类:
# 网络请求类异常 from requests.exceptions import RequestException, Timeout, ConnectionError # Google YouTube API 官方客户端抛出的异常 from googleapiclient.errors import HttpError # 数据解析、校验类异常 from json import JSONDecodeError from django.core.exceptions import ValidationError
替换原「Error 1」位置的异常处理逻辑,按异常粒度分别返回对应提示:
def crawl_youtube_videos(preset_filter): try: # 初始化YouTube客户端、构造请求参数、发起API调用的核心逻辑 youtube = build('youtube', 'v3', developerKey=YOUTUBE_API_KEY) api_resp = youtube.search().list( part="id,snippet", maxResults=preset_filter["max_count"], q=preset_filter["keyword"], relevanceLanguage=preset_filter.get("lang", "zh"), # 其余你预设的筛选参数 ).execute() # 解析响应、入库、返回结果的逻辑 return format_video_data(api_resp) except HttpError as e: # 处理YouTube API返回的官方HTTP错误 err_content = e.content.decode("utf-8") if e.resp.status == 403: if "quotaExceeded" in err_content: tip = "YouTube API当日调用配额已耗尽,请24小时后再试" elif "accessNotConfigured" in err_content: tip = "YouTube API权限未开启,请检查后端接口配置" else: tip = "当前请求无权限访问YouTube资源" elif e.resp.status == 400: tip = "预设筛选参数不合法,请检查规则配置" elif e.resp.status == 404: tip = "查询的频道/视频资源不存在或已被删除" else: tip = f"YouTube接口请求失败,错误码:{e.resp.status}" print(f"Error 1: API请求错误 - {err_content}") # Django视图直接返回统一结构给Vue前端 return JsonResponse({"code": 5001, "msg": tip}) except Timeout: print("Error 1: 请求YouTube API超时") return JsonResponse({"code": 5002, "msg": "连接YouTube服务超时,请检查网络后重试"}) except ConnectionError: print("Error 1: 无法连接YouTube服务") return JsonResponse({"code": 5003, "msg": "无法连接YouTube服务,请检查服务器网络配置"}) except (JSONDecodeError, ValidationError, KeyError, TypeError) as e: print(f"Error 1: 数据处理失败 - {str(e)}") return JsonResponse({"code": 5004, "msg": "视频数据解析异常,请稍后重试"}) except RequestException as e: print(f"Error 1: 网络请求异常 - {str(e)}") return JsonResponse({"code": 5005, "msg": "网络请求异常,请稍后重试"}) except Exception as e: # 最后兜底所有未预判的业务异常 print(f"Error 1: 未预期异常 - {str(e)}\n{traceback.format_exc()}") # 生产环境不要返回原始异常信息,避免泄露敏感配置 return JsonResponse({"code": 5000, "msg": "服务出现未知错误,请联系管理员"})
第三步:补全特殊场景处理
- 如果爬取逻辑跑在Celery异步任务、子线程中,上述try-except必须写在任务执行函数/子线程入口函数的最外层,写在调用任务的外层代码中无法捕获异常
- 前后端交互要统一响应结构,不要让Django抛出默认的500错误页,Vue端直接读取响应中的
msg字段展示给用户即可 - 日志打印不要只输出「Error 1」,要带上异常栈、触发的筛选规则ID、请求参数,方便后续补全漏处理的异常类型
避坑提醒
- 不要写裸
except:做拦截,会拦截所有系统级异常,引发不可预期的服务问题 - 不要把原始异常栈、API密钥这类敏感信息随接口返回给前端,详细错误仅存在服务端日志即可
- 如果你用的是第三方封装的YouTube爬取库,提前查阅对应文档确认其抛出的异常类型,补充到捕获列表中
内容的提问来源于stack exchange,提问作者Revathi Narayankutty
相关产品推荐
相关产品推荐

