Python编程之GET 请求与 POST 请求的本质区别

GET 和 POST 是 HTTP 协议中最常用的两种请求方法,它们在设计目的、使用场景和实现方式上有本质的区别。

本质区别总结

特性 GET 请求 POST 请求
设计目的 获取数据(查询) 提交数据(修改)
参数位置 URL 查询字符串 请求体(Body)
数据可见性 明文显示在 URL 中 隐藏在请求体中
数据长度限制 受 URL 长度限制(约 2048 字符) 无严格限制
安全性 较低(参数暴露) 较高(参数隐藏)
缓存 可被缓存 通常不被缓存
幂等性 幂等(多次执行效果相同) 非幂等(多次执行可能产生不同效果)
书签/分享 可收藏为书签或分享 URL 不可直接收藏或分享
浏览器历史 保留在浏览器历史中 通常不保留

案例说明

案例1:GET 请求 - 搜索功能

import requests

def search_products(keyword, category=None, max_price=None):
    """
    使用GET请求搜索商品 - 适合查询操作
    
    Args:
        keyword (str): 搜索关键词
        category (str): 商品类别筛选
        max_price (float): 最高价格筛选
    """
    # 构建查询参数 - GET请求的参数在URL中可见
    params = {
        'q': keyword,  # 搜索关键词
        'category': category,  # 类别筛选
        'max_price': max_price  # 价格筛选
    }
    
    # 移除值为None的参数
    params = {k: v for k, v in params.items() if v is not None}
    
    try:
        # 发送GET请求 - 参数通过params传递,会显示在URL中
        response = requests.get(
            'https://api.example.com/products/search',  # 搜索API端点
            params=params,  # 查询参数(出现在URL中)
            timeout=10  # 超时设置
        )
        
        response.raise_for_status()  # 检查HTTP错误状态
        
        print(f"请求URL: {response.url}")  # 查看完整的URL(包含参数)
        print(f"状态码: {response.status_code}")
        
        results = response.json()  # 解析JSON响应
        print(f"找到 {len(results)} 个商品")
        
        return results
        
    except requests.exceptions.RequestException as e:
        print(f"搜索失败: {e}")
        return []

# 使用示例
# GET请求示例:搜索价格低于1000元的电子产品
products = search_products(
    keyword='laptop',      # 搜索关键词 - 会在URL中显示
    category='electronics', # 商品类别 - 会在URL中显示
    max_price=1000.0       # 最高价格 - 会在URL中显示
)
# 实际请求的URL可能是:
# https://api.example.com/products/search?q=laptop&category=electronics&max_price=1000.0

案例2:POST 请求 - 用户注册功能

import requests
import json

def register_user(username, email, password):
    """
    使用POST请求注册新用户 - 适合创建操作
    
    Args:
        username (str): 用户名
        email (str): 邮箱地址
        password (str): 密码(敏感信息)
    """
    # 构建请求数据 - POST请求的数据在请求体中,不可见
    data = {
        'username': username,  # 用户名
        'email': email,       # 邮箱地址
        'password': password  # 密码(敏感信息,不应该出现在URL中)
    }
    
    # 设置请求头,指定内容类型为JSON
    headers = {
        'Content-Type': 'application/json'  # 告诉服务器发送的是JSON数据
    }
    
    try:
        # 发送POST请求 - 数据通过json参数传递,隐藏在请求体中
        response = requests.post(
            'https://api.example.com/users/register',  # 用户注册API端点
            json=data,      # 请求数据(隐藏在请求体中,不可见)
            headers=headers, # 请求头
            timeout=10      # 超时设置
        )
        
        response.raise_for_status()  # 检查HTTP错误状态
        
        print(f"状态码: {response.status_code}")
        print("注册成功!")
        
        # 对于POST请求,URL不会包含敏感数据
        print(f"请求URL: {response.url}")  # 这里只会显示基础URL,不含参数
        
        result = response.json()  # 解析JSON响应
        return result
        
    except requests.exceptions.RequestException as e:
        print(f"注册失败: {e}")
        return None

# 使用示例
# POST请求示例:注册新用户(包含敏感信息)
result = register_user(
    username='alice123',           # 用户名
    email='alice@example.com',     # 邮箱
    password='securePassword123'   # 密码(安全地隐藏在请求体中)
)
# 实际请求的URL只是:https://api.example.com/users/register
# 敏感数据(密码)不会出现在URL中,而是在请求体内

案例3:对比示例 - 获取用户信息 vs 更新用户信息

import requests

def get_user_profile(user_id):
    """
    使用GET请求获取用户信息 - 适合读取操作
    """
    # GET请求:获取数据,参数在URL中
    response = requests.get(
        f'https://api.example.com/users/{user_id}',  # URL中包含用户ID
        timeout=5
    )
    
    if response.status_code == 200:
        user_data = response.json()
        print(f"获取用户 {user_id} 的信息成功")
        return user_data
    else:
        print(f"获取用户信息失败,状态码: {response.status_code}")
        return None

def update_user_profile(user_id, updates):
    """
    使用POST请求更新用户信息 - 适合修改操作
    
    Args:
        user_id (str): 要更新的用户ID
        updates (dict): 要更新的字段和值
    """
    # POST请求:修改数据,参数在请求体中
    response = requests.post(
        f'https://api.example.com/users/{user_id}/update',  # 更新端点
        json=updates,  # 更新数据在请求体中
        timeout=5
    )
    
    if response.status_code == 200:
        print(f"更新用户 {user_id} 的信息成功")
        return response.json()
    else:
        print(f"更新用户信息失败,状态码: {response.status_code}")
        return None

# 使用示例
user_id = "12345"

# 使用GET请求获取用户信息(安全,因为只是读取)
user_profile = get_user_profile(user_id)
print(f"用户信息: {user_profile}")

# 使用POST请求更新用户信息(包含敏感或大量数据)
update_result = update_user_profile(user_id, {
    'email': 'newemail@example.com',  # 新邮箱
    'preferences': {'theme': 'dark', 'language': 'zh'},  # 复杂偏好设置
    'bio': '这是一段很长的用户简介...'  # 长文本内容
})

案例4:错误用法对比

import requests

def bad_example_get_with_sensitive_data():
    """
    错误示范:使用GET请求传输敏感信息
    """
    # 错误!敏感信息暴露在URL中
    params = {
        'username': 'alice',
        'password': 'secret123',  # 密码明文出现在URL中!
        'action': 'login'
    }
    
    response = requests.get(
        'https://api.example.com/auth',
        params=params  # 敏感信息会显示在URL中
    )
    
    print(f"不安全的URL: {response.url}")
    # URL可能显示为: https://api.example.com/auth?username=alice&password=secret123&action=login
    # 这非常不安全!

def good_example_post_with_sensitive_data():
    """
    正确示范:使用POST请求传输敏感信息
    """
    # 正确:敏感信息在请求体中
    data = {
        'username': 'alice',
        'password': 'secret123',  # 密码安全地隐藏在请求体中
        'action': 'login'
    }
    
    response = requests.post(
        'https://api.example.com/auth',
        data=data  # 敏感信息在请求体中,不可见
    )
    
    print("安全请求:敏感信息不会出现在URL中")

# 对比演示
print("=== 错误示范 ===")
bad_example_get_with_sensitive_data()

print("\n=== 正确示范 ===")
good_example_post_with_sensitive_data()

如何选择 GET 还是 POST

根据 RESTful API 设计原则:

  1. 使用 GET 当

    • 只是获取数据(查询)
    • 请求是幂等的(多次执行结果相同)
    • 参数较少且不敏感
    • 希望结果可被缓存
  2. 使用 POST 当

    • 创建新资源
    • 更新现有资源
    • 包含敏感信息(密码、令牌等)
    • 有大量数据要发送
    • 操作不是幂等的(多次执行可能产生不同结果)

总结

GET 和 POST 的根本区别在于它们的设计目的数据传递方式

  • GET 用于获取数据,参数在 URL 中,适合查询操作
  • POST 用于提交数据,参数在请求体中,适合创建/修改操作

在实际开发中,应该根据操作的性质和安全需求选择合适的请求方法,遵循 RESTful API 的设计原则,确保应用的安全性和性能。

Logo

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务

更多推荐