零基础读懂 HTTP 与 API:一篇文章打通你的第一次接口调用
零基础读懂 HTTP 与 API:一篇文章打通你的第一次接口调用
适合读者:刚学编程、想调用大模型或其他在线服务,但看到 curl、JSON、API Key 就发懵的新手。
读完你会:看得懂 curl、认得出状态码、会解析嵌套 JSON、理解 REST 风格、会带认证、会处理限流。
先记住一句话:API 就是一个「会办事的网址」。你向它发一个 HTTP 请求,它返回一个 HTTP 响应,响应里通常装着 JSON。所谓「调 API」,就是把请求四要素拼对,再把返回的 JSON 按路径取出来。
很多人第一次接触 API 时,会被一堆术语吓退:URL、Header、Bearer Token、JSON、REST……其实每个词单独看都很简单,只是堆在一起显得可怕。这篇文章把整个过程拆成六步,每一步都带一个能直接运行的例子。跟着走完,你就能完成第一次真实的接口调用。
1. HTTP 请求四要素
任何一个 HTTP 请求,都由下面四样东西组成:
| 要素 | 是什么 | 一句话例子 |
|---|---|---|
| URL | 你要访问的地址 | https://api.example.com/users?page=2 |
| 方法 | 你想干什么 | GET读取、POST创建 |
| Headers | 附加说明和身份 | Authorization、Content-Type |
| Body | 随请求发送的数据 | JSON 字符串,比如用户信息 |
1.1 URL 长什么样
https://api.example.com/v1/users/42?page=2&size=10 │ │ │ │ │ │ │ │ │ └── query 查询参数(问号后面) │ │ │ └────── 路径里的变量:用户 id=42 │ │ └─────────────── 路径(path) │ └──────────────────────────────── 域名:哪台服务器 └────────────────────────────────────── 协议:走 HTTP 还是 HTTPS1.2 四种常用方法
| 方法 | 含义 | 常见场景 | Body 用不用 |
|---|---|---|---|
| GET | 读数据 | 查天气、查用户列表 | 一般不写 |
| POST | 创建数据 / 触发动作 | 发消息、提交表单、调用大模型 | 经常写 |
| PUT | 整体替换更新 | 更新一个用户 | 写 |
| DELETE | 删除 | 删除一条记录 | 一般不写 |
1.3 Headers 里最常看的三个
| Header | 作用 |
|---|---|
Authorization | 放认证信息,最常见的是Bearer 你的key |
Content-Type | 声明 Body 是什么格式,发 JSON 时写application/json |
Accept | 声明你想要什么格式,一般写application/json |
2. 第一次调用:从 curl 到 Python
下面这段是调用大模型 chat API 的标准写法,我们一行一行拆开看:
curl-XPOST"https://api.deepseek.com/chat/completions"\-H"Authorization: Bearer sk-你的key"\-H"Content-Type: application/json"\-d'{ "model": "deepseek-chat", "messages": [ {"role": "user", "content": "你好"} ] }'| curl 片段 | 翻译成人话 |
|---|---|
curl | 用命令行发 HTTP 请求 |
-X POST | 方法用 POST |
"https://..." | 目标 URL |
-H "Authorization: Bearer sk-你的key" | Header 里带 Bearer Token 认证 |
-H "Content-Type: application/json" | Body 是 JSON |
-d '{...}' | Body 内容,用单引号包起来的 JSON |
用 Python 的requests写同一件事:
importrequests resp=requests.post("https://api.deepseek.com/chat/completions",headers={"Authorization":"Bearer sk-你的key","Content-Type":"application/json",},json={"model":"deepseek-chat","messages":[{"role":"user","content":"你好"}],},timeout=30,)print(resp.status_code)print(resp.json())注意:用requests时传json={...}会自动把 Python 字典转成 JSON,并帮你加Content-Type: application/json,不需要手动声明。
3. 看状态码,再决定下一步
状态码是服务器给你的「一句话结论」。看到任何响应,先看状态码,再决定要不要解析 Body。
| 状态码 | 含义 | 新手该怎么做 |
|---|---|---|
| 200 | 成功 | 正常解析 JSON |
| 400 | 客户端参数错 | 检查 URL、参数、Body 字段名,和文档逐字对 |
| 401 | 未认证 | 立刻检查 API key:没填、填错、格式不对、过期了 |
| 403 | 无权限 | key 是对的,但没有权限访问这个资源 |
| 404 | 资源不存在 | 检查 URL 路径拼写,尤其{id}有没有写对 |
| 429 | 限流 | 降低请求频率,等一下再试 |
| 500 | 服务器错误 | 问题大概率在对方服务器,稍后再试 |
把 4xx 和 5xx 分开记:4xx 是你的问题,5xx 是服务器的问题。
处理错误的最小框架:
ifresp.status_code==401:print("认证失败:检查 API key 和 Authorization 头")elifresp.status_code==429:print("限流了:等 1 秒再试,或者降低频率")elifresp.status_code>=500:print("服务器出问题,稍后重试")elifresp.status_code==200:print(resp.json())4. JSON:一棵嵌套的字典/列表树
JSON 只有两种容器:对象(字典)用{}表示,数组(列表)用[]表示。它们可以任意嵌套,所以任何 JSON 都是一棵树。
{"user":{"name":"小明","skills":["Python","API"],"profile":{"city":"Shanghai","level":1}}}解析 JSON 就是「按路径取值」,像在文件系统里找文件一样:
data=resp.json()name=data["user"]["name"]# 小明first_skill=data["user"]["skills"][0]# Pythoncity=data["user"]["profile"]["city"]# Shanghai对应路径写法:
| 想取的值 | 路径 |
|---|---|
| 用户名 | user->name |
| 第一个技能 | user->skills-> 第 0 项 |
| 城市 | user->profile->city |
调试 JSON 最实用的两句:
importjson# 第一次看到新 API,先原样打印整棵树print(json.dumps(data,ensure_ascii=False,indent=2))三个常见翻车点:
- 忘了调
resp.json(),直接对resp.text取下标,会报错或取到字符串。 - 字段名打错,会
KeyError,此时打印整棵树对照文档。 - API 返回的是列表而不是字典,先
data[0]再看。
5. REST 风格:路径、参数和 Body 的分工
REST 是一种常见的 API 设计风格,不是强制规范,但绝大多数现代 API 都长这样。
5.1/users/{id}是什么意思
大括号{id}是「变量」的意思,表示把{id}替换成真实的值:
| 文档写法 | 真实请求 |
|---|---|
GET /users/{id} | GET /users/42 |
GET /repos/{owner}/{repo} | GET /repos/octocat/Hello-World |
DELETE /messages/{id} | DELETE /messages/1001 |
5.2 query 参数怎么拼
URL 里?后面的部分是 query 参数,用&连接多个:
GET https://api.example.com/search?q=python&page=2&size=10 │ │ │ └─────┴──────┴── 三个参数用requests时不要手拼字符串,用params:
resp=requests.get("https://api.example.com/search",params={"q":"python","page":2,"size":10},timeout=15,)5.3 Body 什么时候用
规则很简单:GET 一般不写 Body;POST / PUT / PATCH 要写 Body,因为你要往服务器传数据。Body 通常传 JSON,也可以传表单或文件,具体看文档里的Content-Type。
5.4 一个能立刻动手的 REST 例子:GitHub API
resp=requests.get("https://api.github.com/users/octocat",timeout=15)print(resp.status_code)data=resp.json()print(data["login"])print(data["public_repos"])6. 认证:三种最常见的姿势
6.1 Bearer Token(大多数大模型 API 用这种)
curlhttps://api.example.com/v1/chat/completions\-H"Authorization: Bearer sk-xxxx"headers={"Authorization":"Bearer sk-xxxx"}6.2 Basic Auth
把用户名:密码做 Base64 编码后放进 Header。requests里直接传auth即可:
resp=requests.get("https://api.example.com/private",auth=("user","password"),timeout=15,)6.3 API Key 放在 Header 里
有些 API 用自定义 Header,常见名字有X-Api-Key、api-key、x-api-key:
headers={"X-Api-Key":"你的key"}- List item
三种方式对比:
| 方式 | Header 长什么样 | 谁常用 |
|---|---|---|
| Bearer Token | Authorization: Bearer sk-xxx | DeepSeek、通义千问、豆包、OpenAI |
| Basic Auth | Authorization: Basic base64(用户名:密码) | 老系统、内部工具 |
| API Key in Header | X-Api-Key: xxx | Tavily 等各类 SaaS |
6.4 Key 永远不要硬编码,用 .env
在项目根目录建.env:
DEEPSEEK_API_KEY=sk-你的真实key代码里读取:
fromdotenvimportload_dotenvimportos load_dotenv()api_key=os.getenv("DEEPSEEK_API_KEY")headers={"Authorization":f"Bearer{api_key}"}安装依赖:
uv pip install requests python-dotenv最后在.gitignore里加一行.env,防止把 key 提交到 GitHub。
看到 401 的第一反应:key 没传对。检查顺序:.env里有没有值、变量名拼写、Authorization格式、key 有没有过期。
7. 限流:遇到 429 怎么办
API 不是无限服务,通常有 QPS(每秒请求数)限制。超过限制就会返回 429。别慌,这是最常见的「正常报错」。
最简单的重试逻辑:遇到 429 就等一下再试。
importtimedefpost_with_retry(url,headers,payload,max_tries=3):forattemptinrange(1,max_tries+1):resp=requests.post(url,headers=headers,json=payload,timeout=30)ifresp.status_code==429:wait=attempt*2# 第 1 次等 2 秒,第 2 次等 4 秒,依次递增print(f"第{attempt}次遇到 429,{wait}秒后重试")time.sleep(wait)continueresp.raise_for_status()returnrespraiseRuntimeError("多次重试仍然被限流")三个原则:
- 重试要有上限,不要无限循环。
- 等待时间递增(2 秒、4 秒、8 秒),这叫退避。
- 服务器返回
Retry-After头时,优先按它给的秒数等。
8. 新手最容易踩的八个坑
- 把 key 写死在代码里或提交到 git。用
.env+.gitignore,换台电脑也能迁移。 - 手拼 URL 参数。用
params={"page": 2},让 requests 处理编码。 - 不看状态码直接解析。先
print(resp.status_code),再决定下一步。 - 不设
timeout。网络卡住时脚本会一直挂住,请求都加timeout=30之类。 - 429 后无限重试。设
max_tries,加递增等待。 - 把
resp.text当字典用。先resp.json()得到 Python 结构。 - 忽略
Content-Type。Body 是 JSON 时用json=,发表单时才用data=。 - 看文档跳着读。文档顺序应该是:认证 -> Base URL -> 端点 -> 参数 -> 示例 -> 错误码。
9. 常见报错速查
| 报错 / 现象 | 含义 | 解决 |
|---|---|---|
401 Unauthorized | 认证没通过 | 检查 key、Header 格式、key 是否过期 |
429 Too Many Requests | 请求太频繁 | sleep 后退避重试 |
KeyError: 'xxx' | JSON 里没有这个字段 | 打印整棵树,和文档对照字段名 |
IndexError: list index out of range | 数组是空的或取的位置不对 | 先打印长度,再取值 |
JSONDecodeError | 响应不是 JSON | 打印resp.text,可能返回了错误页面 |
ConnectionError | 连不上服务器 | 检查网络、URL、是否需要代理 |
ReadTimeout | 服务器响应太慢 | 调大 timeout 或换更快的端点 |
No module named 'dotenv' | 没装 python-dotenv | uv pip install python-dotenv |
10. 30 分钟完成第一次调用
- 安装依赖:
uv pip install requests python-dotenv - 5 分钟:调
https://httpbin.org/json,打印slideshow.title。 - 5 分钟:调
https://httpbin.org/post,用json={"name": "我"}看它原样返回什么。 - 5 分钟:在 DeepSeek 平台创建 key,写进
.env,跑通第一句「你好」。 - 10 分钟:把第 7 节的重试函数接进去,故意连续发 20 次请求,观察 429。
- 5 分钟:打开 GitHub API 文档,只靠文档完成
GET /users/{username}。
完成这 6 步,你就真正掌握了调 API 的主干流程。之后再去看任何 API 文档,都会觉得只是换了 URL 和字段名。
总结
- 调 API = 拼对请求四要素 + 解析 JSON。
- 看到响应先看状态码:4xx 检查自己,5xx 等待服务器。
- key 放进
.env管理,429 用退避重试。
下一步建议:选一个免费 API(比如 GitHub API),按「认证 -> Base URL -> 端点 -> 参数 -> 示例 -> 错误码」的顺序读一遍文档,独立完成一次调用。第一次跑通之后,你再看大模型的 chat API,会发现它和 GitHub API 只是长得不同,规则完全一样。
想继续深入,可以看这两个免费视频
- 1 小时全面入门 HTTP 协议(B 站免费课,先建立整体感觉)
- DeepSeek API 的 Python 调用小白详细教程(直接对应本文的认证 + POST + JSON 解析)
