HTTP基础教程:请求方法、状态码、JSON、鉴权、超时、重试与流式返回


title: "HTTP基础教程:请求方法、状态码、JSON、鉴权、超时、重试与流式返回"

date: 2026-04-28

tags:

  • HTTP
  • Python
  • API
  • JSON
  • FastAPI
  • requests
    description: "一篇面向初学者的 HTTP 基础博客教程,系统介绍请求方法、状态码、JSON、鉴权、超时、重试和流式返回,并结合 Python 示例说明实际开发中的常见用法。"

HTTP基础教程:请求方法、状态码、JSON、鉴权、超时、重试与流式返回

做后端、写爬虫、调大模型 API、接第三方平台,几乎绕不开 HTTP。

很多初学者一开始会直接背接口文档,能发请求就算会用,但一旦遇到下面这些问题就容易卡住:

  • 为什么有的接口用 GET,有的用 POST
  • 为什么明明请求发出去了,却返回 401403404500
  • 为什么有的接口参数放在 URL 上,有的放在 JSON 里
  • 为什么调用第三方 API 经常要带 Token
  • 为什么接口偶尔卡死,必须设置超时
  • 为什么失败后有时应该重试,有时反而不能重试
  • 为什么现在很多 AI 接口都支持"流式返回"

这篇文章的目标不是让你死记硬背名词,而是帮你建立一套够用的 HTTP 基础认知,尤其适合:

  • Python 初学者
  • 后端入门同学
  • 爬虫和接口调用初学者
  • 正在学 FastAPI、Flask、requests 的同学

一、HTTP到底是什么

HTTP 全称是 HyperText Transfer Protocol,即超文本传输协议。

你可以把它理解成:

浏览器、客户端、服务端之间约定好的一套"怎么发请求、怎么回响应"的通信规则。

最常见的场景就是:

  1. 客户端发请求
  2. 服务端处理请求
  3. 服务端返回响应

比如你在浏览器输入一个网址,本质上就是浏览器向服务器发起了一次 HTTP 请求。

二、一次HTTP请求里都有什么

一个 HTTP 请求通常包含这些部分:

  • 请求方法
  • 请求路径
  • 请求头
  • 查询参数
  • 请求体

一个 HTTP 响应通常包含这些部分:

  • 状态码
  • 响应头
  • 响应体

看一个最简单的例子:

http 复制代码
GET /users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer your_token_here

服务端可能返回:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json

{"id":123,"name":"Alice"}

这里最值得关注的是三件事:

  • 你用什么方法请求:GET
  • 服务端是否处理成功:200 OK
  • 传输的数据格式是什么:application/json

三、请求方法:GET、POST、PUT、PATCH、DELETE 到底怎么区分

请求方法决定了你"想对资源做什么"。

1. GET:获取资源

GET 用来读取数据,不应该用于修改数据。

常见场景:

  • 获取文章列表
  • 查询用户信息
  • 获取商品详情

例如:

http 复制代码
GET /articles?page=1&page_size=10 HTTP/1.1

特点:

  • 参数通常放在 URL 查询参数里
  • 理论上应该是"安全"的,不修改服务端数据
  • 适合查询场景

2. POST:创建资源或提交数据

POST 常用于创建新资源,或者提交一段需要服务端处理的数据。

例如:

http 复制代码
POST /users HTTP/1.1
Content-Type: application/json

{"name":"Alice","age":20}

常见场景:

  • 创建用户
  • 登录接口
  • 提交表单
  • 调用需要复杂参数的推理接口

3. PUT:整体更新

PUT 通常表示"用新的完整内容替换旧资源"。

例如:

http 复制代码
PUT /users/123 HTTP/1.1
Content-Type: application/json

{"name":"Alice","age":21}

语义上更偏向"整体覆盖"。

4. PATCH:部分更新

PATCH 用于局部更新资源的一部分字段。

例如:

http 复制代码
PATCH /users/123 HTTP/1.1
Content-Type: application/json

{"age":21}

如果只是改某几个字段,PATCH 往往比 PUT 更合适。

5. DELETE:删除资源

DELETE 用于删除资源。

例如:

http 复制代码
DELETE /users/123 HTTP/1.1

6. HEAD 和 OPTIONS

这两个方法初学阶段见得少,但也值得知道:

  • HEAD:和 GET 类似,但只要响应头,不要响应体
  • OPTIONS:询问服务端支持哪些请求方法,浏览器跨域预检时常见

7. 一个最简单的记忆法

方法 含义 常见用途
GET 获取资源
POST 增 / 提交 创建资源、提交任务
PUT 整体改 覆盖更新
PATCH 局部改 部分字段更新
DELETE 删除资源

四、状态码:看懂HTTP响应的第一步

状态码是服务端对本次请求处理结果的简短总结。

1. 2xx:成功

最常见的成功状态码有:

  • 200 OK:请求成功
  • 201 Created:资源创建成功
  • 204 No Content:成功,但没有响应体

例如:

  • 查询成功返回 200
  • 创建新用户成功返回 201
  • 删除成功但不返回内容可以用 204

2. 3xx:重定向

这一类状态码表示客户端需要进一步动作。

常见的有:

  • 301 Moved Permanently:永久重定向
  • 302 Found:临时重定向

浏览器里比较常见,接口开发中一般接触少一点。

3. 4xx:客户端错误

这类状态码通常表示:
请求有问题,责任主要在客户端。

常见的有:

  • 400 Bad Request:请求格式错误、参数不合法
  • 401 Unauthorized:未认证,通常没带 Token 或 Token 无效
  • 403 Forbidden:已认证,但没有权限
  • 404 Not Found:资源不存在
  • 405 Method Not Allowed:请求方法不对
  • 409 Conflict:资源冲突
  • 422 Unprocessable Entity:参数校验失败,FastAPI 中很常见
  • 429 Too Many Requests:请求太频繁,被限流

4. 5xx:服务端错误

这类状态码通常表示:
请求本身可能没问题,但服务端处理失败了。

常见的有:

  • 500 Internal Server Error:服务端内部异常
  • 502 Bad Gateway:网关或上游服务异常
  • 503 Service Unavailable:服务暂时不可用
  • 504 Gateway Timeout:网关等待上游超时

5. 最常见的一组状态码,你最好熟到能脱口而出

状态码 含义 常见原因
200 成功 请求正常
201 创建成功 新资源已生成
400 请求错误 参数不对、格式错误
401 未认证 Token 缺失或失效
403 无权限 账号没有访问权限
404 未找到 路径错了或资源不存在
429 频率过高 被限流
500 服务端异常 代码报错或依赖异常
502 网关错误 上游服务异常
504 网关超时 上游服务太慢

6. 一个开发习惯

看到接口报错时,不要先盯着"返回内容",先看:

  1. 状态码是多少
  2. 请求方法对不对
  3. 路径对不对
  4. 鉴权头带没带
  5. 参数格式对不对

很多问题在这一步就能定位。

五、JSON:现代接口最常见的数据格式

现在大部分 Web API 都用 JSON 传输数据。

1. JSON是什么

JSON 全称是 JavaScript Object Notation,但它并不只属于 JavaScript。

它是一种轻量、可读性强、跨语言通用的数据交换格式。

例如:

json 复制代码
{
  "name": "Alice",
  "age": 20,
  "skills": ["Python", "SQL"],
  "is_active": true
}

2. JSON常见数据类型

JSON 里常见的值类型有:

  • 字符串
  • 数字
  • 布尔值
  • 数组
  • 对象
  • null

3. 请求里怎么传JSON

如果你要向服务端发送 JSON,请求头一般需要带:

http 复制代码
Content-Type: application/json

请求体例如:

json 复制代码
{
  "model": "gpt-4.1",
  "messages": [
    {"role": "user", "content": "你好"}
  ]
}

4. 响应里怎么表示JSON

如果服务端返回的是 JSON,响应头一般会有:

http 复制代码
Content-Type: application/json

5. Python里如何发送JSON

使用 requests 最方便的方式是 json= 参数:

python 复制代码
import requests

url = "https://api.example.com/users"
payload = {"name": "Alice", "age": 20}

response = requests.post(url, json=payload, timeout=10)
print(response.status_code)
print(response.json())

这里的 json=payload 会自动帮你:

  • 把 Python 字典转成 JSON 字符串
  • 帮你设置 Content-Type: application/json

6. data=json= 的区别

这是一个高频面试点,也是高频踩坑点。

  • json=:发送 JSON 数据
  • data=:通常发送表单或原始文本数据

对比:

python 复制代码
requests.post(url, json={"a": 1})
requests.post(url, data={"a": 1})

它们发出去的内容通常并不一样,服务端的解析方式也不一样。

六、鉴权:为什么很多接口必须带Token

并不是所有接口都允许匿名访问。

比如这些场景都需要鉴权:

  • 获取当前登录用户信息
  • 调用付费 API
  • 访问后台管理接口
  • 操作私有资源

鉴权的本质是:

服务端需要确认"你是谁",以及"你有没有权限做这件事"。

1. 最常见的几种鉴权方式

方式一:Bearer Token

这是现代 API 中最常见的方式之一。

请求头通常长这样:

http 复制代码
Authorization: Bearer your_access_token

Python 示例:

python 复制代码
import requests

headers = {
    "Authorization": "Bearer your_access_token"
}

response = requests.get(
    "https://api.example.com/me",
    headers=headers,
    timeout=10,
)
print(response.status_code)
print(response.text)
方式二:Basic Auth

Basic Auth 会把用户名和密码编码后放进请求头中。

Python 示例:

python 复制代码
import requests

response = requests.get(
    "https://api.example.com/private",
    auth=("username", "password"),
    timeout=10,
)
print(response.status_code)
方式三:API Key

有些平台会要求你把 Key 放在请求头或查询参数里。

例如:

http 复制代码
X-API-Key: your_api_key

或者:

http 复制代码
GET /data?api_key=your_api_key HTTP/1.1

通常更推荐放请求头,避免泄露在 URL 日志里。

2. 401403 很容易混

可以这样记:

  • 401:你还没通过身份认证
  • 403:你身份没问题,但你没有权限

例如:

  • 没带 Token:常见 401
  • 带了 Token,但访问管理员接口:常见 403

七、超时:为什么请求不能一直等下去

很多初学者写接口调用时,经常漏掉超时设置:

python 复制代码
requests.get("https://api.example.com/data")

这样写最大的问题是:

如果对方服务卡住了,你的程序可能会一直等下去。

这在下面这些场景里尤其危险:

  • 爬虫批量抓取
  • Web 服务调用第三方接口
  • 定时任务
  • 大模型接口聚合

1. 超时通常分什么

在很多 HTTP 客户端里,超时通常可以细分为:

  • 连接超时:建立连接花太久
  • 读取超时:连接已建立,但服务端返回太慢

requests 支持元组写法:

python 复制代码
import requests

response = requests.get(
    "https://api.example.com/data",
    timeout=(3, 10),
)

这里表示:

  • 连接超时 3 秒
  • 读取超时 10 秒

2. 一个更安全的习惯

无论是脚本、爬虫还是服务端代码,最好都显式设置超时。

例如:

python 复制代码
response = requests.get(url, timeout=10)

或者更细一点:

python 复制代码
response = requests.get(url, timeout=(2, 10))

3. Web服务里为什么更要重视超时

如果你的服务 A 要调用服务 B,而服务 B 很慢:

  • A 的请求线程会被占住
  • 用户会一直等待
  • 并发一多,整个服务吞吐就会下降

所以超时不只是"避免卡死",更是系统稳定性的基础。

八、重试:失败后什么时候该再来一次

接口失败后,重试是很常见的策略,但不是所有失败都能重试。

1. 可以考虑重试的典型场景

  • 网络抖动
  • 临时超时
  • 502503504
  • 短暂性的连接失败
  • 被限流后服务端明确允许稍后重试

2. 不应该盲目重试的场景

  • 参数错误,如 400
  • 没权限,如 401403
  • 资源不存在,如 404
  • 非幂等操作已经成功但客户端没确认,重复提交可能造成副作用

3. 什么叫幂等

幂等可以粗略理解为:

同一个请求执行一次和执行多次,结果一致。

例如:

  • GET 查询通常是幂等的
  • DELETE 在很多设计里也可以视为幂等
  • POST 创建订单通常不是天然幂等的

这意味着:

  • 查询接口失败了,重试一般风险较低
  • 创建订单失败了,直接重试就要谨慎

4. 正确的重试姿势:指数退避

不要失败了立刻狂打一百次。

更合理的策略通常是:

  • 最多重试 2 到 5 次
  • 每次等待时间逐步增加
  • 遇到确定性错误直接停止

5. 一个简单的Python重试示例

python 复制代码
import time
import requests


def fetch_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.get(url, timeout=(3, 10))
            response.raise_for_status()
            return response.json()
        except requests.RequestException as exc:
            is_last = attempt == max_retries - 1
            if is_last:
                raise

            wait_time = 2 ** attempt
            print(f"request failed: {exc}, retry after {wait_time}s")
            time.sleep(wait_time)


data = fetch_with_retry("https://api.example.com/data")
print(data)

6. 一个实用原则

重试是为了对抗"偶发性故障",不是为了掩盖"确定性错误"。

如果请求结构错了、鉴权错了、路径错了,重试 100 次也没意义。

九、流式返回:为什么现在很多AI接口都一边生成一边返回

传统 HTTP 响应通常是:

  1. 客户端发请求
  2. 服务端处理完整个结果
  3. 一次性把完整内容返回

但在很多场景里,用户并不想等到全部完成才看到结果。

比如:

  • 大模型逐字输出答案
  • 实时日志推送
  • 长任务分块返回进度
  • 大文件下载

这时候就会用到流式返回。

1. 什么是流式返回

流式返回指的是:

服务端不是等所有数据都准备好再一次性返回,而是边生成边发送,客户端边接收边处理。

这会显著改善用户感知延迟。

2. 流式返回的价值

  • 首字节更早到达
  • 用户更早看到内容
  • 长任务交互体验更好
  • 更适合聊天、日志、实时反馈场景

3. Python客户端如何接收流式响应

requests 时,可以设置 stream=True

python 复制代码
import requests

response = requests.get(
    "https://api.example.com/stream",
    stream=True,
    timeout=(3, 30),
)

for line in response.iter_lines(decode_unicode=True):
    if line:
        print(line)

这里的关键点是:

  • stream=True:不要一次性把整个响应全部读完
  • iter_lines():按行迭代流式内容

4. 服务端如何返回流式响应

以 FastAPI 为例,可以使用 StreamingResponse

python 复制代码
import asyncio
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()


async def fake_llm_stream():
    chunks = ["你好", ",", "这是", "流式", "返回", "示例。"]
    for chunk in chunks:
        yield chunk
        await asyncio.sleep(0.5)


@app.get("/stream")
async def stream():
    return StreamingResponse(fake_llm_stream(), media_type="text/plain")

客户端访问 /stream 时,就能逐块收到响应,而不是等全部内容拼好。

5. SSE是什么

在流式返回的讨论里,你还经常会见到 SSE

SSE 全称是 Server-Sent Events,它是一种基于 HTTP 的服务端单向推送机制,常用于:

  • AI 聊天输出
  • 消息通知
  • 实时进度

它本质上还是 HTTP,只是响应格式和处理方式更适合持续推送文本事件。

十、把这些概念放到一个完整请求里看

下面是一个更接近真实项目的 Python 请求示例:

python 复制代码
import time
import requests


def call_api():
    url = "https://api.example.com/chat"
    headers = {
        "Authorization": "Bearer your_access_token",
        "Content-Type": "application/json",
    }
    payload = {
        "message": "你好",
        "stream": False,
    }

    for attempt in range(3):
        try:
            response = requests.post(
                url,
                headers=headers,
                json=payload,
                timeout=(3, 15),
            )

            if response.status_code == 429:
                wait_time = 2 ** attempt
                time.sleep(wait_time)
                continue

            response.raise_for_status()
            return response.json()
        except requests.RequestException:
            if attempt == 2:
                raise
            time.sleep(2 ** attempt)


result = call_api()
print(result)

这里你能同时看到几个 HTTP 基础点:

  • 用的是 POST
  • 请求体是 JSON
  • 带了 Bearer Token
  • 设置了超时
  • 对可恢复失败做了重试
  • 最终解析 JSON 响应

十一、初学者最容易踩的坑

1. 忘记设置超时

这会导致程序在异常情况下长期卡住。

2. 把 data=json= 搞混

表面都能发请求,但服务端收到的内容可能完全不是你想要的。

3. 遇到报错只看返回文本,不看状态码

状态码往往是定位问题的第一线索。

4. 看到失败就无脑重试

先判断是不是可恢复错误,再决定要不要重试。

5. 流式返回时还按普通响应处理

如果服务端本来是分块返回,你却用一次性读取,体验和处理逻辑都会变差。

6. 把敏感信息拼到URL里

例如把 Token、密码、API Key 放在查询参数中,容易出现在日志、浏览器历史和代理记录里。

十二、如果你在学Python,建议这样练HTTP

按下面顺序练习会比较扎实:

  1. requests 调一个公开 GET 接口
  2. 自己写一个 POST JSON 请求
  3. 练习读取状态码和响应头
  4. 给请求加上超时和异常处理
  5. 练习 Bearer Token 鉴权
  6. 写一个简单重试函数
  7. 用 FastAPI 写一个普通接口和一个流式接口

如果这些都能独立写出来,你对 HTTP 的理解就已经不只是"会调接口"了。

十三、总结

HTTP 基础最重要的不是背概念,而是建立正确的请求和排错思维。

这篇文章最核心的内容可以压缩成下面几句话:

  • 请求方法决定你想对资源做什么
  • 状态码决定你应该先从哪里排查问题
  • JSON 是现代 API 最常见的数据格式
  • 鉴权决定你有没有资格访问接口
  • 超时是稳定性的底线,不能省
  • 重试只适合处理偶发性故障,不适合掩盖确定性错误
  • 流式返回适合长任务、实时输出和 AI 场景

如果你后面要学:

  • 爬虫
  • FastAPI
  • 调用大模型 API
  • 微服务接口联调

那这些 HTTP 基础几乎都会反复用到。

把这一层打牢,后面很多内容都会顺很多。

相关推荐
水木流年追梦2 小时前
CodeTop Top 300 热门题目10-验证IP地址
python·网络协议·tcp/ip·算法·leetcode
lifewange5 小时前
RPC 是什么
网络·网络协议·rpc
想成为优秀工程师的爸爸10 小时前
第十九篇技术笔记:UDP——相思传得快,飞鸽传书在
笔记·网络协议·tcp/ip·udp·信息与通信
0xR3lativ1ty13 小时前
关闭公网IP的两种方式
网络协议·tcp/ip·php
2401_8734794016 小时前
固件升级如何按地区分批推送?IP地址查询定位决定升级策略
网络协议·tcp/ip·php
net3m3316 小时前
所有esp_websocket_client_send。。。的地方都加锁,就不容易websocket 断线重连
网络·websocket·网络协议
Jiangxl~16 小时前
IP数据云如何为不同行业提供精准IP查询与风险防控解决方案?
网络·网络协议·tcp/ip·算法·ai·ip·安全架构
你觉得脆皮鸡好吃吗16 小时前
HTTP (XSS前简单了解)
网络·网络协议·http·网络安全学习
摸鱼仙人~20 小时前
HTTP 状态码系统拆解
网络·网络协议·http