API 入门指南:从零理解软件之间的对话方式
学完这篇教程,你将能够独立调用第三方 API 完成实际任务,理解 REST API 的工作原理,搞清楚 API Key 和 Token 的区别,并且知道怎么保护自己的凭证安全。我会带你从最基础的概念开始,一步步动手调用真实 API,最后再分享一些实战中踩过的坑。
不管你是开发者想接入支付接口,还是产品经理需要理解技术方案,甚至是普通用户想自动化一些重复操作,这篇教程都能帮你建立对 API 的直观认知。
一、你将学到什么
学完这篇教程,你能够独立完成以下任务:
- 调用一个真实的 REST API:我会带你用 curl 命令调用一个公开的天气 API,亲眼看到数据是怎么返回的
- 用代码调用 API:写一段 Python 代码,自动获取股票价格或者发送请求到服务器
- 区分三种 API 类型:REST API、GraphQL、WebSocket 各有什么优劣,什么时候该用哪个
- 理解认证机制:搞清楚 API Key 和 Token(JWT)分别用在什么场景,为什么不能把 Key 硬编码在代码里
- 处理 API 响应:学会解析返回的 JSON 数据,提取你需要的信息
- 处理常见错误:超时、401 报错、429 限流,这些情况发生后怎么排查和解决
这些技能看起来不多,但已经足够让你应付日常开发中 80% 的 API 相关需求了。剩下的 20% 属于高并发、网关设计这些进阶话题,我们放在最后简单提一下方向。
二、前置知识
在开始之前,你需要具备以下基础知识:
- 会用命令行:知道怎么打开终端、输入命令、查看输出结果。Windows 用户用 PowerShell 或者 CMD,Mac 和 Linux 用户用 Terminal
- 懂一点 HTTP 基础:知道 GET、POST 这些词大概是什么意思,不需要深入理解,能区分就行
- 接触过编程:不要求精通,但至少写过几行代码,知道变量、函数、循环这些概念
- JSON 是什么:知道 JSON 是一种存储数据的格式长什么样,能认出键值对和数组就行
如果这些你都不熟悉,也没关系。我会在讲解过程中穿插解释必要的概念,但不会深入展开。你完全可以先跟着步骤做,遇到不懂的概念再回头查资料。
另外,这篇教程全程使用免费公开的 API,不会产生任何费用,也不需要你注册付费账号。
三、环境准备
开始实战之前,先把工具准备好。以下是你需要安装的软件:
- curl:命令行工具,用来发送 HTTP 请求。macOS 和 Linux 系统自带,Windows 10 及以上版本也内置了。验证方法是在终端输入
curl --version,如果看到版本号就说明已安装 - Python 3.7+:编程语言,用来写代码调用 API。下载地址是 python.org,安装时记得勾选"Add Python to PATH"。验证方法:
python --version - pip:Python 包管理工具,通常随 Python 一起安装。验证方法:
pip --version
如果你用的是 Linux 系统,大概率已经装好了 curl 和 Python。可以用下面的命令快速检查:
# 检查 curl
curl --version
# 检查 Python
python3 --version
# 检查 pip
pip3 --version
预期输出大概是这样的:
curl 7.79.1 (x86_64-apple-darwin) libcurl/7.79.1
Python 3.11.4
pip 23.2.1
版本号可能略有不同,只要不是报错提示"command not found"就行。
如果你的 Windows 系统没有 curl,可以下载 Git for Windows,它会自带 Git Bash 环境,里面包含 curl。或者你也可以直接用 Python 的 requests 库来发请求,跳过 curl 这一步。
四、核心概念
在动手之前,先把几个核心概念讲清楚。这些概念看起来枯燥,但理解了它们能帮你少走很多弯路。
什么是 API
API 的全称是 Application Programming Interface,翻译过来是"应用程序编程接口"。但这个翻译太抽象了,我换个说法:API 就是软件之间的对讲机。
想象一下这个场景:你在外卖 App 上点了一份炸鸡,商家收到订单后开始制作,同时骑手开始取餐。这些动作能自动衔接起来,靠的不是人工打电话通知,而是不同系统之间通过 API 在"对话"。你的订单信息通过 API 传给商家的接单系统,商家完成制作后通过 API 通知骑手可以取餐了。
所以 API 的本质就是:定义一套规则,让不同的软件可以互相请求数据或者触发操作。你不需要知道对方系统是怎么实现的,只需要按照它规定的格式发送请求,就能得到响应。
HTTP 方法
调用 API 的过程,本质上是在发送 HTTP 请求。HTTP 定义了几种不同的请求方法,最常用的有四种:
- GET:获取数据。比如查询天气、获取用户信息。GET 请求通常不会修改服务器上的数据
- POST:创建新数据。比如注册账号、提交表单、发送消息
- PUT/PATCH:更新数据。PUT 是完整替换,PATCH 是部分修改
- DELETE:删除数据。比如删除一条记录
初学者最常接触的是 GET 和 POST。GET 请求的参数放在 URL 里面,POST 请求的参数放在请求体里面。
请求和响应
一次完整的 API 调用包含以下几个部分:
请求(Request):
- URL:请求的地址,比如
https://api.example.com/users - Method:请求方法,GET/POST/PUT/DELETE
- Headers:请求头,包含认证信息、内容类型等
- Body:请求体,POST/PUT 请求携带的数据
响应(Response):
- Status Code:状态码,200 表示成功,404 表示找不到,401 表示未授权
- Headers:响应头,包含服务器返回的元信息
- Body:响应体,返回的数据,通常是 JSON 格式
状态码是排查问题的关键,下面是一些常见的:
| 状态码 | 含义 | 常见场景 |
|---|---|---|
| 200 | 成功 | 请求正常处理完毕 |
| 201 | 已创建 | POST 请求成功创建了新资源 |
| 400 | 请求错误 | 参数格式不对、缺少必填字段 |
| 401 | 未授权 | 没有提供认证信息或认证信息无效 |
| 403 | 禁止访问 | 有认证但没有权限 |
| 404 | 找不到 | 请求的资源不存在 |
| 429 | 请求过多 | 触发了限流,需要降频 |
| 500 | 服务器错误 | 对方服务器出问题了 |
三种 API 风格对比
现在市面上最常见的三种 API 风格是 REST、GraphQL 和 WebSocket,它们各有特点:
| 特性 | REST API | GraphQL | WebSocket |
|---|---|---|---|
| 通信方式 | 请求-响应 | 请求-响应 | 双向实时 |
| 数据获取 | 固定端点返回固定数据 | 客户端指定需要什么字段 | 服务器主动推送 |
| 适用场景 | 标准的 CRUD 操作 | 多资源聚合查询 | 实时聊天、股票行情、在线游戏 |
| 学习成本 | 低 | 中 | 中 |
| 缓存支持 | 容易 | 困难 | 不适用 |
REST API 是目前最主流的方式,80% 以上的公开 API 都是 REST 风格。GraphQL 由 Facebook 开发,适合数据关系复杂的场景,比如社交网络。WebSocket 用于需要实时更新的场景,比如聊天软件和在线协作工具。
这篇教程我们主要讲 REST API,因为它最通用、最容易入门。
五、实战步骤(第一部分)
好了,概念讲完了,开始动手。我们先用 curl 调用一个真实的 API,感受一下整个流程。
1. 调用公开的天气 API
我们用 Open-Meteo 这个免费天气 API,不需要注册就能用。打开终端,输入以下命令:
curl "https://api.open-meteo.com/v1/forecast?latitude=39.9042&longitude=116.4074¤t_weather=true"
这个 URL 的意思是:查询纬度 39.9042、经度 116.4074(即北京)的当前天气。让我拆解一下 URL 的结构:
https://api.open-meteo.com/v1/forecast:API 的基础地址latitude=39.9042:纬度参数longitude=116.4074:经度参数current_weather=true:请求当前天气数据
预期输出(格式化的 JSON):
{
"latitude": 39.9042,
"longitude": 116.4074,
"timezone": "Asia/Shanghai",
"current_weather": {
"temperature": 18.5,
"windspeed": 12.3,
"winddirection": 180,
"weathercode": 3,
"time": "2024-10-15T14:00"
}
}
恭喜你,你刚刚完成了一次 API 调用!返回的数据包含温度、风速、风向、天气代码和时间。
2. 发送带参数的 POST 请求
刚才的 GET 请求没有携带认证信息,因为这个 API 是完全公开的。现在我们试试发送一个 POST 请求。
很多 API 需要你在请求体里发送 JSON 数据,比如用户注册、发送消息等场景。我们用一个模拟 API 来练习:
curl -X POST "https://jsonplaceholder.typicode.com/posts" \
-H "Content-Type: application/json" \
-d '{"title":"我的第一篇文章","body":"这是内容","userId":1}'
解释一下这些参数:
-X POST:指定请求方法为 POST-H "Content-Type: application/json":告诉服务器请求体是 JSON 格式-d '{"title":"...","body":"...","userId":1}':请求体的数据
预期输出:
{
"title": "我的第一篇文章",
"body": "这是内容",
"userId": "1",
"id": 101
}
服务器返回了创建成功的资源,其中 id: 101 是新创建的文章 ID。注意 userId 变成了字符串类型,这是该 API 的特性,不同的 API 处理方式可能不同。
3. 用 Python 调用 API
命令行用熟了之后,我们用 Python 来做同样的事情。Python 的优势是可以处理更复杂的逻辑,比如循环调用、解析嵌套数据、结合业务逻辑等。
首先安装 requests 库:
pip install requests
然后创建一个文件 weather.py,内容如下:
import requests
# 调用天气 API
url = "https://api.open-meteo.com/v1/forecast"
params = {
"latitude": 39.9042,
"longitude": 116.4074,
"current_weather": True
}
response = requests.get(url, params=params)
# 检查响应状态
if response.status_code == 200:
data = response.json()
weather = data["current_weather"]
print(f"当前温度:{weather['temperature']}°C")
print(f"风速:{weather['windspeed']} km/h")
print(f"更新时间:{weather['time']}")
else:
print(f"请求失败,状态码:{response.status_code}")
运行这个脚本:
python weather.py
预期输出:
当前温度:18.5°C
风速:12.3 km/h
更新时间:2024-10-15T14:00
这就是一个完整的 API 调用流程:构造请求、发送请求、检查状态、解析响应。
六、实战步骤(第二部分)
接下来我们进阶一点,试试需要认证的 API。
1. 理解 API Key
很多付费或半付费的 API 需要 API Key 来识别调用者身份、统计用量、防止滥用。API Key 就像一张入场券,没有它你就进不去。
假设我们要调用一个虚拟的"翻译 API",它需要 API Key。正常情况下你需要去官网注册获取,但这里我们用环境变量的方式来模拟这个流程。
创建一个文件 translate.py:
import os
import requests
# 从环境变量读取 API Key(安全做法)
api_key = os.environ.get("TRANSLATION_API_KEY")
if not api_key:
print("请设置 TRANSLATION_API_KEY 环境变量")
print("macOS/Linux: export TRANSLATION_API_KEY=your_key_here")
print("Windows PowerShell: $env:TRANSLATION_API_KEY='your_key_here'")
exit(1)
# 构造请求
url = "https://api.example-translate.com/v1/translate"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
data = {
"text": "Hello, world!",
"target_language": "zh"
}
response = requests.post(url, headers=headers, json=data)
if response.status_code == 200:
result = response.json()
print(f"原文:{data['text']}")
print(f"译文:{result['translated_text']}")
else:
print(f"请求失败:{response.status_code} - {response.text}")
注意这里的认证方式:Authorization: Bearer {api_key}。这是 OAuth 2.0 的标准做法,叫做 Bearer Token。Bearer 后面跟的就是你的凭证。
2. 理解 Token 和 Session
API Key 适合机器对机器的调用,但有时候我们需要区分不同用户。比如一个笔记应用,后端 API 需要知道请求是哪个用户发的,这时候就要用 Token。
Token(最常见的是 JWT)比 API Key 更复杂,它包含了三部分:Header、Payload、Signature。Payload 里面可以存储用户 ID、过期时间等信息。
一个典型的使用场景是这样的:
- 用户登录时,后端验证用户名密码,成功后返回一个 Token
- 后续请求带上这个 Token,后端解析后就知道是谁在请求
- Token 过期后需要重新登录获取新的 Token
API Key 更像是"通行证",一旦泄露就有风险。Token 则有过期时间,而且可以包含更丰富的信息。
3. 处理分页数据
很多 API 返回的数据量很大,一次性全部返回会造成网络和性能问题。这时候会用到分页。
比如我们要获取一个列表的前两页数据:
import requests
base_url = "https://jsonplaceholder.typicode.com/posts"
all_posts = []
for page in range(1, 3):
response = requests.get(base_url, params={"_page": page, "_limit": 10})
if response.status_code == 200:
posts = response.json()
all_posts.extend(posts)
print(f"第 {page} 页获取成功,共 {len(posts)} 条")
else:
print(f"第 {page} 页获取失败")
break
print(f"\n总共获取 {len(all_posts)} 条数据")
预期输出:
第 1 页获取成功,共 10 条
第 2 页获取成功,共 10 条
总共获取 20 条数据
分页参数的具体名称因 API 而异,常见的有 page + per_page、offset + limit、cursor 等,要看具体 API 的文档。
七、关键代码/配置详解
这一节对刚才的代码做一些深入解释,帮你理解为什么要这样写。
requests 库的核心参数
requests.get() 和 requests.post() 是最常用的两个方法,它们的参数含义如下:
requests.get(
url, # 必填,请求地址
params=None, # URL 参数,会自动拼接到 URL 后面
headers=None, # 请求头,比如认证信息、Content-Type
timeout=None, # 超时时间,单位秒
cookies=None, # Cookie
verify=True # 是否验证 SSL 证书
)
params 参数特别方便,它会自动把字典转成 URL 查询参数。比如 params={"page": 1, "limit": 10} 会变成 ?page=1&limit=10。
请求头的正确设置
很多新手会忽略请求头的重要性,导致请求失败或者返回奇怪的数据。最重要的两个请求头是:
Content-Type:告诉服务器请求体的格式。发送 JSON 时设为application/jsonAuthorization:携带认证信息
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer your_token_here",
"Accept": "application/json" # 告诉服务器希望返回 JSON 格式
}
超时设置很重要
网络请求可能因为各种原因变慢甚至卡死,一定要设置超时时间:
# 设置 5 秒超时
response = requests.get(url, timeout=5)
# 或者分别设置连接超时和读取超时
response = requests.get(url, timeout=(3.05, 27))
第一个数字是连接超时,第二个是读取超时。不设置超时可能导致程序永远卡住。
错误处理的正确姿势
不要假设请求一定会成功,要做好错误处理:
try:
response = requests.get(url, timeout=10)
response.raise_for_status() # 如果状态码不是 200,会抛出异常
data = response.json()
except requests.exceptions.Timeout:
print("请求超时,请检查网络连接")
except requests.exceptions.ConnectionError:
print("连接失败,可能是服务器不可用或地址错误")
except requests.exceptions.HTTPError as e:
print(f"HTTP 错误:{e}")
except requests.exceptions.JSONDecodeError:
print("返回数据不是有效的 JSON 格式")
except Exception as e:
print(f"未知错误:{e}")
八、效果验证
怎么确认你的 API 调用成功了?下面几个方法帮你验证。
查看原始响应
有时候 JSON 格式化后反而看不清结构,可以直接打印原始文本:
print(response.text) # 原始文本
print(response.content) # 字节内容
检查响应头
响应头里有很多有用信息,比如缓存策略、限流信息等:
print(response.headers)
输出示例:
{'Content-Type': 'application/json', 'X-RateLimit-Remaining': '98', ...}
X-RateLimit-Remaining 就是剩余请求次数,很重要的信息。
用 curl 的 verbose 模式
如果想看请求的完整细节(包括请求头、响应头),用 -v 参数:
curl -v "https://api.open-meteo.com/v1/forecast?latitude=39.9&longitude=116.4¤t_weather=true"
输出会包含:
> GET /v1/forecast?latitude=39.9&longitude=116.4¤t_weather=true HTTP/1.1
> Host: api.open-meteo.com
> User-Agent: curl/7.79.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
箭头 > 表示发送的内容,< 表示接收的内容。
模拟器测试
开发阶段可以用 httpbin.org 这个网站测试你的请求,它会把你发送的内容原样返回:
curl -X POST "https://httpbin.org/post" \
-H "Content-Type: application/json" \
-d '{"name": "张三", "age": 25}'
返回结果会包含你发送的所有信息,方便调试。
九、常见问题与排错
这一节总结了我和很多开发者在实际使用中最常遇到的问题及解决方案。
问题 1:curl 命令报 "SSL certificate problem"
完整报错:
curl: (60) SSL certificate problem: unable to get local issuer certificate
原因分析:系统的 CA 证书没有更新或者不完整,导致无法验证服务器的 SSL 证书。
解决方法:临时跳过证书验证(仅限开发环境):
curl -k "https://api.open-meteo.com/v1/forecast?latitude=39.9&longitude=116.4¤t_weather=true"
或者更新系统的 CA 证书包。macOS 用户可以运行:
sudo /usr/bin/cert-sync /etc/ssl/cert.pem
Windows 用户安装最新版的 curl 后通常能解决这个问题。
问题 2:Python 请求报 "ConnectionError"
完整报错:
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='api.example.com', port=443): Max retries exceeded
原因分析:可能是网络问题、DNS 解析失败、或者防火墙阻止了连接。
解决方法:按顺序排查。首先检查网络是否正常:
ping api.example.com
如果 ping 不通,说明是网络层面的问题。如果能 ping 通但代码请求失败,试试增加超时时间并重试:
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=0.5)
session.mount('https://', HTTPAdapter(max_retries=retries))
response = session.get(url, timeout=10)
问题 3:返回 401 Unauthorized
完整报错:
{"error": "Invalid API key", "code": 401}
原因分析:认证信息无效或缺失。可能的原因包括:API Key 写错了、Token 过期了、请求头格式不对。
解决方法:确认认证信息的格式。大多数 API 接受两种格式:
# 方式 1:放在请求头
headers = {"Authorization": "Bearer your_key_here"}
# 方式 2:放在 URL 参数(不推荐,不安全)
url = "https://api.example.com/data?api_key=your_key_here"
先在官方文档确认 API 要求的格式,然后仔细检查你的代码。
问题 4:返回 429 Too Many Requests
完整报错:
{"error": "Rate limit exceeded", "retry_after": 60}
原因分析:请求频率超过了 API 的限制。大多数公开 API 都有速率限制,比如每分钟 60 次、每小时 1000 次等。
解决方法:在代码里实现重试逻辑,收到 429 后等待一段时间再试:
import time
def fetch_with_retry(url, max_retries=3):
for i in range(max_retries):
response = requests.get(url)
if response.status_code == 200:
return response.json()
elif response.status_code == 429:
wait_time = int(response.headers.get("Retry-After", 60))
print(f"触发限流,等待 {wait_time} 秒...")
time.sleep(wait_time)
else:
raise Exception(f"请求失败:{response.status_code}")
raise Exception("重试次数用尽")
问题 5:JSON 解析失败
完整报错:
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
原因分析:服务器返回的不是 JSON,可能是 HTML 错误页面、空响应、或者服务器宕机了。
解决方法:先打印原始响应看看是什么:
print(f"状态码:{response.status_code}")
print(f"响应内容:{response.text[:500]}") # 只打印前 500 字符
有时候服务器会返回 200 但内容是错误提示,这种情况下 response.json() 会失败,但 response.text 能看到真实内容。
十、进阶方向
学完这篇教程,你已经掌握了 API 的基础知识。接下来可以从以下几个方向继续深入:
1. 深入 REST API 设计
如果你想自己设计和实现 API,需要了解 REST 的最佳实践。比如如何设计 URL 结构(RESTful 风格)、如何返回合适的 HTTP 状态码、如何做版本控制等。推荐学习 Roy Fielding 的 REST 论文和 Richardson Maturity Model。
2. 尝试 GraphQL
GraphQL 是 REST 的替代方案,特别适合前端需要灵活获取数据的场景。如果你做的是 Web 或移动端开发,GraphQL 可以显著减少请求次数和数据量。可以从 Apollo Client 入手,结合一个简单的 GraphQL 服务器来练习。
3. 了解 API 网关和微服务
在企业级应用中,API 网关是流量入口,负责认证、限流、路由等工作。常见的网关有 Kong、APISIX、AWS API Gateway 等。理解网关的概念对架构设计很有帮助。
4. 学习 API 安全
实际项目中,API 安全是重中之重。需要了解的内容包括:OAuth 2.0 和 OpenID Connect、JWT 的正确使用方式、API 签名机制、HTTPS 的正确配置、CORS 策略等。这些话题都可以单独写一篇文章,这里就不展开了。
5. 探索 WebSocket 实时通信
需要实时数据推送的场景,比如在线聊天、股票行情、协作编辑,WebSocket 是更好的选择。可以尝试用 Socket.io 或者原生 WebSocket API 写一个简单的聊天室,感受一下双向通信的魅力。
好了,API 入门指南到这里就结束了。希望你学完之后能够独立调用第三方 API,理解请求和响应的结构,知道怎么处理认证和错误。这些技能在日常开发中非常实用。
如果有任何疑问或者踩到了新的坑,欢迎随时来交流。技术这东西,多动手、多踩坑才能真正掌握。
