2026/10/25 14:21:13

DeepSeek API 图像与文本分类调用实战:环境、请求与排错

DeepSeek API 图像与文本分类调用实战:环境、请求与排错 简介面向具备Python基础、希望将云端机器学习服务接入实际项目的开发者这份docx文档聚焦DeepSeek API在图像分类与文本分类两类任务中的调用方法。内容围绕注册获取API密钥、安装requests与Pillow、构造POST请求及设置Authorization请求头展开并结合代码示例说明图像上传、JSON文本提交、响应解析与错误排查的完整流程可帮助读者理解HTTP接口调用与分类结果字段提取。资源包共1个docx文件约17KB以步骤说明与代码片段结合的方式组织便于按章节查阅和本地实践。目前已有2676人学习说明其在API接入类内容中具有一定参考价值。读者可从中获得两类分类任务的请求构造思路、图像尺寸预处理与结果解析方法以及遇到无效密钥、请求格式错误时的基本排查方向适合用于快速搭建图像或文本分类应用原型。1. 一张 3MB 的相机原图让我在 DeepSeek API 调用上卡了四十分钟第一次跑 DeepSeek API 调用代码不到三十行环境也就 Python 加 requests、Pillow 两个库我却在一张 3MB 的相机原图上卡了四十多分钟接口一直回 400日志只有一句参数错误。图像分类和文本分类这两条链路装起来不复杂难的是版本、编码、请求体三处对不齐——requests 的 files 和 json 不能混着传Pillow 读出来的 RGB 和带 alpha 的 PNG 不是一回事密钥写进环境变量也可能带个换行。这套环境适合会写 Python、想把分类能力接进原型的开发者装不好的典型症状是本地能跑、换台机器就 401或者换张图就 413。下面按我实际装机的顺序来。2. 装环境先定版Python、requests、Pillow 的安装与版本取舍2.1 用虚拟环境把 Python 版本锁在 3.103.12这件事我吃过亏。系统自带的 Python 3.8 上装 Pillowpip 会退到一个很老的版本去编译装完Image.resize的默认重采样行为和新版本不一致同一张图两次跑出来的信心分数差了好几个点排查了半天才发现是解释器版本问题。所以现在我的做法很固定解释器落在 3.103.12 这个区间。下限 3.10 是因为大部分二进制 wheel 在这个版本上覆盖最全装 Pillow 不会触发源码编译上限不碰 3.13 及更新版本是因为新解释器刚出来那阵轮子生态往往要慢半拍为一个分类脚本去折腾编译链不值当。装之前先确认手上是哪个解释器别想当然。多版本共存的机器上python和python3指向的可能不是同一个东西后面所有命令我都统一用python -m pip这种模块调用写法避开 PATH 里的歧义。# 先确认解释器版本低于 3.9 直接换别硬装 python3 -V # 在项目目录下建独立环境避免与系统包互相污染 python3 -m venv .venv # 激活Linux / macOS source .venv/bin/activate # 激活Windows PowerShell # .venv\Scripts\Activate.ps1 # 升级 pip 本身老 pip 解析依赖时给出的冲突提示经常是误导 python -m pip install --upgrade pipvenv生成的目录里带的是一份独立的 site-packages装坏了直接rm -rf .venv重建不会波及系统环境这是它比pip install --user更值得用的原因。激活成功的标志是命令行提示符前面出现(.venv)如果没出现先别急着往下装多半是激活脚本没跑对。Windows 上这一步最容易翻车PowerShell 默认执行策略禁止运行脚本Activate.ps1会报「无法加载文件因为在此系统上禁止运行脚本」。解决方式不是去改全局策略而是在当前窗口临时放开# 只对当前进程生效关掉窗口就恢复比改全局策略安全 Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass .\.venv\Scripts\Activate.ps1如果连 PowerShell 都不想动直接用.venv\Scripts\python.exe这个绝对路径去跑脚本效果一样只是命令长一点。我一般会把这个路径记在便签上出问题时用它来确认「到底是环境没激活还是包真没装上」。2.2 requests 与 Pillow 的安装命令和版本钉法两个库的安装命令本身没什么可说的值得说的是版本怎么写。完全放开版本约束pip install requests Pillow在个人机器上没事一旦进了 CI 或者换了台机器拉到的可能是半年前的大版本行为差异足够让你怀疑人生。我习惯用「下限 上限」的区间写法下限保证用到的能力存在上限挡住破坏性变更。# requests 2.31 起 timeout 元组、Session 复用行为稳定 # Pillow 10 起 resize 的重采样常量换成了 Image.Resampling老代码要留意 python -m pip install requests2.31,3 Pillow10.0,12requests2.31这个下限不是随便定的早期版本在连接超时和读取超时的拆分上行为不够清晰而我们后面要传timeout(5, 30)这种元组老版本对元组的支持不完全一致容易出现「设了 30 秒却卡了两分钟」的怪现象。上限3则是挡住 requests 下一个大版本避免某天自动升级后请求行为变化。Pillow 的12同理图片处理库的大版本改动往往集中在编码器和色彩模式转换上正是我们要用的部分。装完立刻验证别等写代码时才发现装了个空壳# 打印实际版本确认装的是 venv 里的那一份 python -c import requests, PIL; print(requests, requests.__version__); print(Pillow, PIL.__version__)如果这一步报ModuleNotFoundError九成是环境没激活装到系统 Python 里去了用python -c import sys; print(sys.executable)看一眼解释器路径就能确认。Pillow 装不上是另一类问题Linux 上常见于缺libjpeg、zlib这些系统库导致 pip 回退到源码编译然后失败Windows 上则是缺 C 编译器。我的处理顺序是先升级 pip再强制只用预编译轮子最后才考虑补系统库。# 强制只用二进制轮子装不上就立刻报错而不是默默去编译 python -m pip install --only-binary:all: Pillow10.0,12 # Debian / Ubuntu 上确实需要源码编译时先补齐这几个开发库 # sudo apt-get install -y libjpeg-dev zlib1g-dev libfreetype6-dev--only-binary:all:这个参数的价值在于把「静默编译十分钟然后失败」变成「三秒内告诉你没有轮子」省掉大量等待。真碰上必须编译的场景再回头补系统库顺序别搞反。2.3 requirements.txt 与装坏了的回滚单人调试可以随手pip install但只要这套环境要在第二台机器上复现就该有一份文件把依赖写死。我的做法是两层requirements.txt写区间约束给人看、给新机器装requirements.lock.txt写精确版本给自己回滚用。# requirements.txt —— 区间约束允许小版本漂移 requests2.31,3 Pillow10.0,12# 按约束装 python -m pip install -r requirements.txt # 装完后把当前精确版本冻结下来作为可回滚的快照 python -m pip freeze requirements.lock.txtfreeze出来的文件包含所有传递依赖的精确版本哪天某个库自动升级把调用弄挂了python -m pip install -r requirements.lock.txt就能一键回到装好那天的状态。这是这套环境里唯一的「后悔药」成本几乎为零但真出事的时候能省掉一小时。再说一个很常见的坏味道同一个包在系统目录和 venv 里各装了一份运行时到底加载的哪份全靠运气。判断依据就是sys.executable和sys.pathpython -c import requests; print(requests.__file__)打印出的路径必须落在.venv目录下落在/usr/lib/python3/dist-packages之类的地方就说明串了。出现这种情况先deactivate再重新激活还不行就把.venv删了重建比重装包快得多。提示不要在激活失败的状态下反复pip install那只会往系统环境里堆垃圾让后续判断更难。3. 配置收口API Key、请求 URL、Headers 三处必须对齐3.1 API Key 进环境变量别写死在第十七行密钥硬编码在脚本里本地跑着没事一旦提交到仓库、发给同事、贴进工单就是一次标准的泄露。我现在的规矩是代码里永远只有一个读取函数密钥只从环境变量来。# Linux / macOS当前会话有效关掉终端就没了适合临时调试 export DEEPSEEK_API_KEY你的密钥 # 需要长期生效写进 shell 配置文件后再 source 一次 echo export DEEPSEEK_API_KEY你的密钥 ~/.zshrc source ~/.zshrc# Windows当前窗口有效 $env:DEEPSEEK_API_KEY 你的密钥 # 永久写入用户环境变量注意要重开终端才生效 setx DEEPSEEK_API_KEY 你的密钥读取这一端我写了个带检查的函数比直接os.environ[DEEPSEEK_API_KEY]多做三件事去掉首尾空白、拦掉空值、把长度异常的情况打出来。别小看这几行密钥从聊天窗口复制过来尾部带一个换行Authorization头就会变成Bearer sk-xxx\n服务端返回的往往只是一句笼统的「Invalid API key」肉眼根本看不出来。import os def load_api_key() - str: raw os.environ.get(DEEPSEEK_API_KEY, ) key raw.strip() # 复制粘贴最容易带进来的换行和空格 if not key: raise RuntimeError(DEEPSEEK_API_KEY 未设置先 export 再运行) if raw ! key or \n in raw: # 只提示异常不打印密钥本身 print(警告密钥首尾含空白字符已自动清理) return key这里用.get()而不是下标取值是为了自己抛出可读的错误信息KeyError: DEEPSEEK_API_KEY这种报错对新手很不友好看不出是环境变量的问题还是代码的问题。另外密钥的长度和前缀可以打印内容绝不能进日志出问题时我只看len(key)和前四位。配套要做的是把本地环境文件挡在版本控制之外。哪怕你用的是.env方案也先加一条忽略规则# .gitignore .venv/ .env *.log3.2 URL 与 Content-Type图像走 files文本走 json原文给了两个地址一个是/v1/classify一个是/v1/text_classify并且明确写了「这只是示例具体 URL 请查阅文档」。这一点必须原样保留接口路径以官方文档为准本文里的地址只用来演示拼接方式。真正决定请求能不能通的是「请求体形态」和「Content-Type」这一对必须匹配。图像上传走multipart/form-data用files参数文本分类走application/json用json参数。两者混用是新手最常见的翻车点。任务类型传参方式Content-Type是否手动设置备注图像分类files{image: (...)}multipart/form-data; boundary...否交给 requests 生成手动设成 json 会直接 400/415文本分类json{text: ...}application/json否json会自动带自己dumps时注意编码通用请求头Authorization: Bearer key是两种任务都要我特意在表里写了「是否手动设置」这一列因为原文示例里 headers 同时带了Authorization和Content-Type: application/json而请求用的又是files。这两者在实际发送时是冲突的multipart必须带 boundary 参数手写的application/json会把这个 boundary 覆盖掉服务端解析不出文件字段。我的做法是只保留Authorization剩下的交给库。提示接口路径和字段名以官方文档当前版本为准示例地址只用于说明请求结构不要当成固定值抄进生产代码。还有个小细节是 URL 拼接。自己拼 base_url 时https://api.deepseek.com/v1后面接/classify和接classify结果完全不同前者正常后者变成v1classify。下面这个写法能同时容错带斜杠和不带斜杠两种配置def join_url(base: str, path: str) - str: # 统一去掉重复斜杠避免 v1//classify 这种 404 return base.rstrip(/) / path.lstrip(/)3.3 一份 config.py 把配置收口再抽一个 call 函数配置散落在各个脚本里改一次地址要翻五个文件这种事干过一次就够了。我习惯在项目根目录放一个config.py把三样东西收进去密钥、基地址、超时。超时写成元组是我踩过坑之后固定下来的习惯(5, 30)表示连接阶段最多等 5 秒、读完响应最多等 30 秒只写一个数字的话连接阶段和读取阶段共用一个值遇到大图上传时很容易在建立连接阶段就超时。# config.py import os API_KEY os.environ.get(DEEPSEEK_API_KEY, ).strip() BASE_URL os.environ.get(DEEPSEEK_BASE_URL, https://api.deepseek.com/v1) TIMEOUT (5, 30) # (连接超时, 读取超时)单位秒 MAX_RETRIES 3在这个基础上再抽一个统一的调用函数把鉴权头、超时、重试、日志一次性做掉。中间章里我最推荐先写的就是这个函数后面图像和文本两条链路都复用它代码量能砍掉一半。# client.py import logging, time, requests from config import API_KEY, BASE_URL, TIMEOUT, MAX_RETRIES log logging.getLogger(deepseek) def call(path: str, *, json_bodyNone, files_factoryNone, retriesMAX_RETRIES): url BASE_URL.rstrip(/) / path.lstrip(/) headers {Authorization: fBearer {API_KEY}} for attempt in range(1, retries 1): files files_factory() if files_factory else None # 每次重试重新开文件 try: resp requests.post(url, headersheaders, jsonjson_body, filesfiles, timeoutTIMEOUT) if resp.status_code 429 or resp.status_code 500: raise requests.HTTPError(f可重试状态码 {resp.status_code}) return resp except (requests.Timeout, requests.ConnectionError, requests.HTTPError) as e: if attempt retries: raise wait 2 ** (attempt - 1) # 1s、2s、4s 退避 log.warning(第 %s 次失败%s%s 秒后重试, attempt, e, wait) time.sleep(wait)几个参数值得单独说。files_factory传进来的是函数而不是文件对象因为文件流读过一次就到底了重试时再用同一个对象上传服务端收到的会是空 body——这个坑我在第 5 章还会展开。2 ** (attempt - 1)是标准的指数退避第一次失败等 1 秒、第二次 2 秒、第三次 4 秒比固定间隔更不容易把限速撞得更狠。429和5xx单独判出来重试4xx里的 400、401、413 则原样返回因为这几类重试一百次也没用属于请求本身有问题。日志这块我一般只记三样请求路径、状态码、耗时。请求体和密钥不进日志。有次为了查一个 400 把完整请求打了进去结果日志被同事顺手贴到公开频道密钥就这么泄了从那以后这条规矩我没破过。4. 两类请求跑通图像分类的 files 上传与文本分类的 json 提交4.1 Pillow 预处理三件事尺寸、色彩模式、体积模型对输入的要求通常写得比较含糊——「适当尺寸」「常见格式」。落到代码上就是三件事把图缩到固定尺寸、统一成三通道、把文件压到合理体积。原文示例用的是 224×224并且用了Image.resize这个思路是对的只是少了两个必要步骤。第一是色彩模式。手机截图、设计稿导出的 PNG 常常带 alpha 通道模式是RGBA直接存成 JPEG 会抛OSError: cannot write mode RGBA as JPEG。第二是 EXIF 方向手机拍的竖图在像素层面可能是横的靠 EXIF 标记旋转不处理的话上传后分类结果会莫名其妙。第三是体积3MB 的原图缩到 224 之后通常只剩几十 KB这一步本身就把 413 挡掉了大半。from PIL import Image, ImageOps def prepare_image(src: str, dst: str, size(224, 224)) - str: with Image.open(src) as im: im ImageOps.exif_transpose(im) # 按 EXIF 把方向摆正 im im.convert(RGB) # RGBA / P 模式统一成三通道 im im.resize(size, Image.LANCZOS) # 高质量下采样 im.save(dst, formatJPEG, quality88, optimizeTrue) return dstImage.LANCZOS是缩小时最稳的重采样方式比默认的BICUBIC慢一点但边缘更干净对分类精度有小幅正向影响。quality88是我反复试出来的平衡点再往上体积涨得快、肉眼与模型都分辨不出optimizeTrue会额外做一遍无损压缩多花几十毫秒换更小的文件。注意 Pillow 10 之后常量搬到了Image.Resampling.LANCZOS老代码里的Image.ANTIALIAS已经删了如果搜到的是老教程照着抄会直接报AttributeError。我一般还会加一道体积闸门超过阈值先压再传而不是等接口回 413import os def ensure_under(path: str, limit_mb: float 1.0) - str: # 超过限制就降质量重存最多降三档 if os.path.getsize(path) limit_mb * 1024 * 1024: return path from PIL import Image with Image.open(path) as im: for q in (70, 55, 40): im.save(path, formatJPEG, qualityq, optimizeTrue) if os.path.getsize(path) limit_mb * 1024 * 1024: break return path4.2 图像请求requests.post 的 headers 与 files 组合到这一步才真正发请求。图像上传的关键是files参数的三元组写法字段名、文件名、MIME 类型。字段名必须和接口文档一致示例里是image文件名影响不大但最好带上正确扩展名某些服务端会据此判断格式MIME 类型写image/jpeg要和实际存的文件格式对上。import requests from config import API_KEY, BASE_URL, TIMEOUT def classify_image(image_path: str) - dict: url BASE_URL.rstrip(/) /classify # 路径以官方文档为准 headers {Authorization: fBearer {API_KEY}} # 不要手写 Content-Type with open(image_path, rb) as f: files {image: (image.jpg, f, image/jpeg)} resp requests.post(url, headersheaders, filesfiles, timeoutTIMEOUT) if resp.status_code ! 200: raise RuntimeError(fHTTP {resp.status_code}: {resp.text[:200]}) return resp.json()用with open(...)是必须的不关文件句柄在批量处理几千张图时会直接把文件描述符耗光报Too many open files。headers里只留鉴权Content-Type完全交给 requests——它在发files时会自动生成multipart/form-data; boundary----WebKitFormBoundary...这个 boundary 是随机串手写不可能对。还有个常见误区是「先把图片读成字节流塞进 JSON」。原文正文里提到「通常图像数据会作为文件上传而非直接放入 JSON 中」这句话是对的二进制转 base64 再塞 JSON 会让体积膨胀三分之一还得自己处理编码没有任何好处。除非接口文档明确要求 base64否则一律走files。4.3 文本请求json 参数与中文编码文本这条链路简单得多一个json参数就完事。它的好处是内部会自动做序列化并设置正确的Content-Type: application/json不用你操心。需要留意的只有编码中文文本如果自己json.dumps再传ensure_ascii默认是True会被转成一堆\uXXXX虽然服务端通常能解析但日志里完全没法看。def classify_text(text: str) - dict: url BASE_URL.rstrip(/) /text_classify # 路径以官方文档为准 headers {Authorization: fBearer {API_KEY}} # 直接用 jsonrequests 负责序列化和 Content-Type resp requests.post(url, headersheaders, json{text: text}, timeoutTIMEOUT) if resp.status_code ! 200: raise RuntimeError(fHTTP {resp.status_code}: {resp.text[:200]}) return resp.json()如果你因为某些原因必须手动序列化比如要复用已经构造好的字符串写法是datajson.dumps(payload, ensure_asciiFalse).encode(utf-8)并且手动补Content-Type: application/json; charsetutf-8。少了charset那一截部分服务端会按 latin-1 解析中文直接变乱码。这就是我说的「编码对不齐」的具体形态肉眼看到的是一堆问号实际是字符集声明缺失。4.4 响应解析label 与 confidence 怎么用接口成功时返回的 JSON 结构是这样的{ status: success, data: { label: cat, confidence: 0.98 } }label是分类标签confidence是置信度0.98 表示模型有 98% 的把握。解析代码要防两件事一是data字段缺失二是 HTTP 200 但业务层返回失败。后者是最阴的因为resp.status_code 200会骗过所有只看状态码的代码。def parse_result(body: dict, threshold: float 0.6): if body.get(status) ! success: # 业务层失败也会是 200必须单独判 raise RuntimeError(f接口返回失败{body.get(message, 未知原因)}) data body.get(data) or {} label data.get(label) conf data.get(confidence) if label is None or conf is None: raise ValueError(f响应结构不符合预期{body}) conf float(conf) return {label: label, confidence: conf, reliable: conf threshold}threshold0.6是我在业务里常用的默认值低于这个分数的结果我一般会转人工复核而不是直接写进下游系统。这个值没有标准答案看你的容错成本——分类错了只是显示个图标阈值可以放到 0.5错了要触发扣款或者告警那就调到 0.8 以上。把reliable这个布尔值单独返回比在调用方到处写if conf 0.6更好维护。5. 排查与避坑五条踩过的真实记录5.1 请求阶段的三条第一条本地能跑换台机器就 401。现象是同一份代码在同事机器上始终返回Invalid API key日志里看不出任何异常。原因有两个层面一是新机器上环境变量根本没设os.environ.get返回空字符串拼出来的头变成Bearer服务端自然拒绝二是用setx在 Windows 上设了变量但没重开终端当前进程读到的还是旧值。解决办法是把密钥检查前置成启动时的断言跑主流程之前先打印len(key)长度为 0 就直接退出并提示怎么设置而不是让它走到请求里变成一句含糊的鉴权失败。第二条图像请求返回 400 或 415文本请求却正常。现象是同一个call函数文本分类跑得通图像分类一直报格式错误。原因是请求头里手写了Content-Type: application/json同时又传了files两者冲突服务端收到的 multipart 缺少 boundary解析不出文件字段。解决就是图像这条路径的 headers 里只留AuthorizationContent-Type一律交给 requests 生成。判断是否属于这一类看resp.text里有没有boundary或者multipart字样有就是这个问题。第三条重试机制上线后第二次上传永远是空文件。现象是开了指数退避第一次超时后重试服务端返回「图片为空」或者「无法解码」。原因是第一次请求已经把文件流读到了末尾重试时传的是同一个文件对象read()直接返回b。解决办法就是第 3 章那个files_factory的写法把「打开文件」这件事包成函数每次重试重新open一次。这个 bug 特别隐蔽因为没有重试的时候一切正常只有网络抖动时才偶发。5.2 响应与网络的两条第四条HTTP 200 但结果是空的。现象是状态码判断全部通过resp.json()也能解析但取data.label时抛KeyError。原因是业务层错误同样用 200 返回错误信息在status和message字段里比如{status: error, message: Invalid API key}。解决是把「HTTP 层成功」和「业务层成功」拆成两道判断先看状态码再看body[status]两个都过了才去取data。这条我建议写进公共解析函数里别指望每个调用点都记得判。第五条批量处理时零星出现 429越重试越多。现象是单张图跑得好好的一上批量就有百分之几的请求失败加上重试之后失败率反而上升。原因是并发数开得太高短时间打出去的请求超过了配额重试又进一步推高了瞬时压力。解决分两步把并发压到 24 这个量级先测确认稳定后再逐步往上加重试必须带退避time.sleep(2 ** n)这种不能用固定 100 毫秒疯狂重发。另外记得区分 429 和 5xx前者是限速、后者是服务端抖动处理策略不一样但都需要退避。6. 装完怎么验证跑通一份自检脚本和三道必须过的关环境装完、代码写完别急着往业务里接。我习惯先跑一遍自检把「环境问题」和「业务问题」分开不然一个 401 能让你在业务逻辑里找两小时。自检脚本不长五步任何一步失败就带着明确的提示退出。# selfcheck.py import os, sys, requests from PIL import Image def main() - int: # 第一关密钥是否就位 key os.environ.get(DEEPSEEK_API_KEY, ).strip() if not key: print([FAIL] DEEPSEEK_API_KEY 未设置); return 1 print(f[OK] 密钥长度 {len(key)}前四位 {key[:4]}) # 第二关依赖版本是否落在预期区间 import PIL print(f[OK] requests {requests.__version__} / Pillow {PIL.__version__}) # 第三关本地预处理链路是否通 Image.new(RGB, (640, 480), (128, 128, 128)).save(_probe.jpg, quality88) with Image.open(_probe.jpg) as im: assert im.mode RGB and im.size (640, 480) print([OK] Pillow 读写正常) # 第四关文本分类链路 from client import call r call(text_classify, json_body{text: smoke test}) print(f[{OK if r.status_code 200 else FAIL}] 文本接口 HTTP {r.status_code}) # 第五关图像分类链路用刚生成的探针图 from client import call as call2 import io def opener(): return {image: (probe.jpg, open(_probe.jpg, rb), image/jpeg)} r2 call2(classify, files_factoryopener) print(f[{OK if r2.status_code 200 else FAIL}] 图像接口 HTTP {r2.status_code}) return 0 if r.status_code 200 and r2.status_code 200 else 2 if __name__ __main__: sys.exit(main())这个脚本的设计思路是「先本地、后远程先便宜、后昂贵」。前三关完全不发网络请求密钥没设、版本不对、Pillow 装坏都能在本地就拦下来后两关才真正打接口而且图像那关用的是自己生成的纯色探针图不依赖任何业务素材。退出码分三档0 全通、1 环境问题、2 接口问题方便直接塞进 CI 或者部署前钩子。配套我还留了一张人工核对表有些东西脚本测不出来只能靠眼看检查项期望结果不通过时的第一反应.venv是否激活提示符带(.venv)sys.executable指向项目内重新激活别在这状态下装包密钥是否进了版本库git grep搜不到密钥明文立刻轮换密钥并清理历史图像预处理输出模式 RGB、尺寸 224×224、体积小于 1MB检查是否漏了convert(RGB)响应解析status success且data.label有值先看message字段别只看状态码重试行为断网跑一次能看到退避日志且最终抛错检查文件流是否被复用真正让我养成这套习惯的是有一次把「HTTP 200 就当成功」的代码发上了预发环境跑了两天才有人发现分类结果全是空字符串——接口一直在返回业务错误只是状态码是 200。从那以后我每次接新接口都强制先跑一遍这个自检脚本五步全绿才动业务代码宁可多花十分钟也不想再在业务层里追一个其实是鉴权引起的空值。希望这套东西能帮到你少走我走过的那四十分钟。本文还有配套的精品资源点击获取