4.5 KiB
4.5 KiB
tags, create time
| tags | create time | ||||
|---|---|---|---|---|---|
|
2026-04-24 18:41 |
HTTP 协议
概述
HTTP(HyperText Transfer Protocol)是浏览器和服务器之间通信的"语言"。理解 HTTP 是理解 Web 工作原理的第一步。
思考题:你在浏览器地址栏输入 https://www.google.com 后按下回车,HTTP 协议在这个过程中扮演了什么角色?
正文
1. HTTP 请求结构
请求行 → 方法 + URL + 协议版本
请求头 → Key-Value 对,携带元信息
空行
请求体 → GET 请求通常为空,POST/PUT 有数据
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Length: 42
{"name": "Alice", "age": 25}
2. HTTP 方法(动词)
| 方法 | 语义 | 幂等性 | 典型场景 |
|---|---|---|---|
GET |
读取数据 | ✅ 是 | 获取列表、详情 |
POST |
创建资源 | ❌ 否 | 提交表单、创建用户 |
PUT |
全量更新 | ✅ 是 | 完整替换一个资源 |
PATCH |
部分更新 | ❌ 否 | 修改用户某个字段 |
DELETE |
删除资源 | ✅ 是 | 删除用户、删除文章 |
graph LR
A[CRUD] -->|Create| B[POST]
A -->|Read| C[GET]
A -->|Update| D[PUT / PATCH]
A -->|Delete| E[DELETE]
提问: 为什么
GET请求要求"幂等"和"安全"(不修改服务器状态)?如果GET请求能删除数据,会发生什么安全问题?
3. 状态码分类
1xx → 信息性(处理中)
2xx → 成功(200 OK, 201 Created)
3xx → 重定向(301 永久, 302 临时)
4xx → 客户端错误(400 参数错误, 401 未认证, 403 无权限, 404 不存在)
5xx → 服务端错误(500 服务器内部错误, 502 网关错误, 503 服务不可用)
实战要点: 前端开发最常遇到的是 401(Token 过期)和 403(权限不足),理解它们的区别很重要:401 是"你是谁?",403 是"你是谁,但你不能做这件事。"
4. 常用请求头
| Header | 说明 |
|---|---|
Content-Type |
请求体格式(application/json / application/x-www-form-urlencoded) |
Authorization |
认证信息(Bearer <token>) |
Accept |
期望的响应格式 |
Cookie |
客户端存储的会话数据 |
Referer |
来源页面(用于防盗链) |
User-Agent |
客户端信息(浏览器/设备) |
5. RESTful 设计原则
RESTful 不是严格的规范,而是一组设计哲学:
资源命名用名词复数,动词用 HTTP 方法:
GET /api/users → 获取所有用户
GET /api/users/:id → 获取单个用户
POST /api/users → 创建用户
PUT /api/users/:id → 更新用户(全量)
PATCH /api/users/:id → 更新用户(部分)
DELETE /api/users/:id → 删除用户
graph TD
A[RESTful 核心原则] --> B["资源用 URL 表示<br/>(名词复数)"]
A --> C["操作用 HTTP 方法表示<br/>(GET/POST/PUT/DELETE)"]
A --> D["状态码表示结果<br/>(200/201/404/500)"]
A --> E["无状态<br/>(每次请求独立)"]
A --> F["JSON 作为数据交换格式"]
思考: 为什么 RESTful 要求 URL 中用名词而不是动词?
GET /api/deleteUser/5和DELETE /api/users/5哪个更符合 RESTful 原则?为什么?
6. Go 后端处理 HTTP 请求示例
package main
import (
"encoding/json"
"net/http"
)
// 定义请求结构体
type CreateUserRequest struct {
Name string `json:"name"`
Age int `json:"age"`
}
func handleCreateUser(w http.ResponseWriter, r *http.Request) {
// 只接受 POST 方法
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 解析请求体
var req CreateUserRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
// 处理业务逻辑...
// 创建用户
// 返回 201 Created
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(map[string]interface{}{
"id": 1,
"name": req.Name,
"age": req.Age,
})
}
关联笔记
- API 设计 — 基于 HTTP 协议的 API 设计方法
- 数据库基础 — HTTP 请求最终需要操作数据库
- 30.areas/finance/Investment lessons/2024.Current trading lessons.md