[web]GET和POST(介绍)

412 阅读3分钟

在 Web 开发中,GETPOST 是两种最常用的 HTTP 请求方法

理解 HTTP 中的 GETPOST 方法是 Web 开发的核心基础。

下面从本质、工作原理到实际应用进行深度解析:


一、本质区别:设计目的

GETPOST
本质获取数据(只读操作)提交数据(写操作)
哲学"请给我这个资源""请处理我提交的这些数据"
类比在图书馆查询书籍目录(不改变书籍)向图书馆提交新书入库申请(改变库存)

二、技术特性深度对比

1. 数据传输位置

### GET 请求示例
GET /search?q=apple&page=1 HTTP/1.1
Host: example.com

数据在 URL 中
?q=apple&page=1 直接暴露在地址栏

### POST 请求示例
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=admin&password=123456

数据在请求体(Body)中
敏感信息不会显示在地址栏

2. 数据长度限制

GETPOST
限制✅ 约 2048 字符❌ 理论上无上限
原因URL 长度被浏览器限制数据通过 Body 分段传输
场景适合简短查询参数适合文件上传、长文本提交

3. 安全性对比

graph LR
A[请求方式] --> B{安全?}
B -->|GET| C[❌ 不安全]
C --> D[参数在URL中暴露<br>历史记录可查<br>易被网络嗅探]
B -->|POST| E[⛔ 相对安全]
E --> F[数据在Body中<br>需HTTPS加密保护<br>但仍可能被恶意抓包]

重要认知:POST 不是绝对安全!敏感数据必须配合 HTTPS 加密

4. 幂等性(Idempotence)

# GET 是幂等的(多次调用结果相同)
def handle_get_request():
    return database.read_data()  # 不会改变系统状态

# POST 是非幂等的(每次可能产生新结果)
def handle_post_request():
    database.create_new_order()  # 每次调用创建新订单
GETPOST
幂等✅ 是❌ 否
影响可重复请求需防重复提交

三、底层协议行为

1. 浏览器缓存机制

sequenceDiagram
    Browser->>Server: GET /product/123
    Server-->>Browser: 200 OK (带缓存头)
    Browser->>Browser: 缓存响应结果
    用户再次访问->>Browser: 直接读缓存
  • GET:可被缓存(Cache-Control 控制)
  • POST:不会被缓存(刷新时浏览器会警告重复提交)

2. TCP 数据包结构差异

GET 请求数据包:
[ TCP Header | IP Header | HTTP Header | URL参数 ] 

POST 请求数据包:
[ TCP Header | IP Header | HTTP Header | 空行 | Body数据 ]

✅ POST 比 GET 多一次 TCP 数据包传输(首次发送 Header,二次发送 Body)


四、如何选择?决策流程图

graph TD
A[需要执行什么操作?] --> B{是否改变服务器状态?}
B -->|否| C[使用 GET]
B -->|是| D{是否含敏感数据/文件?}
D -->|否| E[考虑 PUT/PATCH]
D -->|是| F[使用 POST]
C --> G[示例:搜索、页面跳转]
F --> H[示例:登录、支付、上传]

五、Flask 中的实战示例

GET 请求处理

@app.route('/search', methods=['GET'])  # 可省略 methods
def search():
    # 从URL获取参数: /search?q=python
    query = request.args.get('q', '')  # args 解析查询字符串
    results = db.search(query)
    return render_template('results.html', results=results)

POST 请求处理

from flask import request

@app.route('/register', methods=['POST'])
def register():
    # 从表单体获取数据
    username = request.form['username']  # form 解析表单数据
    password = request.form['password']
    
    # 创建新用户(非幂等操作)
    user = User.create(username, password)
    return redirect(url_for('login'))

混合处理 GET/POST

@app.route('/contact', methods=['GET', 'POST'])
def contact():
    if request.method == 'POST':
        # 处理表单提交
        name = request.form['name']
        email = request.form['email']
        send_email(name, email)
        return "提交成功!"
    else:
        # 显示空表单(GET请求)
        return render_template('contact_form.html')

六、必须遵守的安全规范

  1. 永远不要用 GET 传输敏感数据

    # 危险!密码暴露在URL
    @app.route('/login?user=admin&pass=123456')  # ❌
    
    # 正确做法
    @app.route('/login', methods=['POST'])       # ✅
    
  2. POST 也需要防御 CSRF 攻击

    <!-- 在表单中添加CSRF令牌 -->
    <form method="POST">
      <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
      <!-- 其他字段 -->
    </form>
    
  3. 关键操作使用 POST + 幂等校验

    # 防止重复提交订单
    @app.route('/order', methods=['POST'])
    def create_order():
        if 'order_token' not in session:
            abort(400)
        
        token = request.form.get('token')
        if token != session['order_token']:
            abort(403)  # 禁止重复提交
        
        # 处理订单...
        session.pop('order_token', None)  # 销毁令牌
    

终极理解心法

把 HTTP 方法看作对资源的操作指令:

  • GET = SELECT * FROM ... (数据库查询)
  • POST = INSERT INTO ... (数据库插入)

就像你不会用 SELECT 语句删除数据一样,永远不要用 GET 请求执行写入操作。遵循这个原则,你就掌握了 RESTful 设计的精髓。