请谈谈 HTTP 中的请求方法(GET、POST、PUT、DELETE等),它们的区别是什么?

一、HTTP方法核心概念

HTTP请求方法是客户端向服务器表达操作意图的核心标识,遵循RFC 7231等规范定义。

正确使用方法可提升API语义清晰度,降低前后端协作成本。以下是常见方法特性对比表:

方法 幂等性 安全性 请求体支持 典型应用场景
GET 获取资源列表/详情
POST 创建资源/触发复杂操作
PUT 全量替换资源
DELETE 删除指定资源
PATCH 部分更新资源
二、核心方法详解与代码示例
1. GET:安全的数据获取
复制代码
// 获取用户列表(带查询参数)
async function fetchUsers(page = 1) {
  const query = new URLSearchParams({ page })
  const response = await fetch(`/api/users?${query}`)
  
  if (!response.ok) {
    throw new Error(`获取失败: ${response.status}`)
  }
  return response.json()
}

安全实践

  • 避免在URL中传递敏感参数(会被浏览器历史记录)
  • 对数组参数进行编码处理:ids[]=1&ids[]=2
2. POST:非幂等的资源创建
复制代码
// 创建新用户(带CSRF保护)
async function createUser(userData) {
  const csrfToken = document.querySelector('meta[name="csrf-token"]').content
  
  const response = await fetch('/api/users', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify(userData)
  })

  if (response.status === 201) {
    return response.headers.get('Location') // 获取新资源路径
  }
  
  const error = await response.json()
  throw new Error(error.message)
}

开发陷阱

  • 多次点击提交按钮会导致重复创建(需前端防抖+服务端幂等校验)
  • 文件上传需使用multipart/form-data格式
3. PUT:幂等的全量替换
复制代码
// 更新用户全部信息
async function updateUser(userId, newData) {
  const response = await fetch(`/api/users/${userId}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(newData)
  })

  if (response.status === 204) {  // 204 No Content常见响应
    return true
  }
  
  if (response.status === 409) {  // 版本冲突处理
    return handleConflict(await response.json())
  }
  
  throw new Error('更新失败')
}

注意事项

  • 要求客户端传递完整资源对象
  • 需配合ETagLast-Modified处理并发冲突
4. DELETE:资源删除操作
复制代码
// 带确认的删除操作
async function deleteResource(resourceId) {
  if (!confirm('确定删除?')) return
  
  const response = await fetch(`/api/resources/${resourceId}`, {
    method: 'DELETE'
  })

  if (response.status === 204) {
    showToast('删除成功')
    refreshList()
  } else if (response.status === 403) {
    showError('权限不足')
  }
}

特殊场景

  • 软删除建议返回200+状态字段而非204
  • 批量删除推荐使用POST + 请求体(避免URL长度限制)
三、高级方法实战应用
1. PATCH:部分更新
复制代码
// 使用JSON Patch格式
async function updateUserEmail(userId, newEmail) {
  const patch = [
    { op: 'replace', path: '/email', value: newEmail }
  ]
  
  const response = await fetch(`/api/users/${userId}`, {
    method: 'PATCH',
    headers: { 'Content-Type': 'application/json-patch+json' },
    body: JSON.stringify(patch)
  })
  
  // 处理422 Unprocessable Entity验证错误
}

规范建议

  • 使用标准格式:JSON Patch(RFC 6902)或JSON Merge Patch
  • 避免在数组中指定索引(易引发并发问题)
2. OPTIONS:预检请求处理
复制代码
// CORS预检请求处理示例
app.options('/api/*', (req, res) => {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  res.status(204).end()
})

性能优化

  • 设置Access-Control-Max-Age减少预检次数
  • 避免在Authorization头携带过大token
四、常见误区与最佳实践
1. 方法误用反模式
复制代码
// 错误示例:用GET执行删除操作
fetch(`/api/users/123?action=delete`, { method: 'GET' })

// 正确做法:使用DELETE方法
fetch(`/api/users/123`, { method: 'DELETE' })

风险点

  • 搜索引擎爬虫可能触发危险操作
  • 浏览器预加载可能导致意外执行
2. RESTful API设计规范
复制代码
// 资源嵌套路由示例
POST /articles/123/comments  // 创建评论
GET  /articles/123/comments  // 获取评论列表
PUT  /articles/123/comments/456  // 更新指定评论

设计原则

  • 使用名词而非动词定义端点
  • 版本控制通过Header或URL路径实现(如/v1/resource
3. 幂等性保障机制
复制代码
// 支付接口幂等处理(使用唯一ID)
async function processPayment(orderId, idempotencyKey) {
  const response = await fetch('/api/payments', {
    method: 'POST',
    headers: {
      'Idempotency-Key': idempotencyKey  // 服务端存储该Key保证幂等
    },
    body: JSON.stringify({ orderId })
  })
  
  // 处理409 Conflict重复请求
}

实现方案

  • 服务端存储请求指纹(方法+路径+参数+Key)
  • 客户端生成UUID作为幂等Key
五、调试与性能优化
  1. Network面板分析

    • 查看请求方法列确认是否误用
    • 过滤method:POST快速定位提交请求
  2. 性能优化策略

    // 批量操作使用PATCH代替多个PUT
    const bulkUpdate = [
    { id: 1, op: 'replace', path: '/name', value: 'Alice' },
    { id: 2, op: 'remove', path: '/address' }
    ]

    fetch('/api/users/bulk', {
    method: 'PATCH',
    body: JSON.stringify(bulkUpdate)
    })

  3. 自动化测试验证

    // 使用Jest测试方法合规性
    test('用户创建必须使用POST方法', async () => {
    const response = await app.inject({
    method: 'PUT',
    url: '/api/users',
    payload: mockUserData
    })
    expect(response.statusCode).toBe(405) // Method Not Allowed
    })

六、总结与团队规范建议
  1. 强制规范

    • 敏感操作禁止使用GET方法
    • 更新操作严格区分PUT/PATCH语义
  2. 协作流程

    • API文档必须明确每个端点的允许方法
    • 使用Swagger/OpenAPI生成交互式文档
  3. 监控报警

    • 对405 Method Not Allowed进行监控
    • 统计非常用方法(如HEAD/OPTIONS)的调用频率
  4. 安全加固

    • 严格限制TRACE/CONNECT方法
    • 对敏感接口启用双重认证(如删除操作)

参考资料:

  • RFC 7231: HTTP/1.1 Semantics and Content
  • RESTful Web APIs by Leonard Richardson
  • OWASP REST Security Cheat Sheet
相关推荐
君鼎16 分钟前
muduo库TcpServer模块详解
linux·网络·c++
开***能17 分钟前
包装设备跨系统兼容:Profinet转Modbus TCP的热收缩包装机改造方案
服务器·网络·tcp/ip
zyp24681023 分钟前
深入理解TCP与UDP:协议对比、头部结构与连接管理
网络协议·tcp/ip·udp
卡戎-caryon31 分钟前
【MySQL】02.数据库基础
linux·网络·数据库·mysql·存储引擎
技术宝哥1 小时前
从另一个视角理解TCP握手、挥手与可靠传输
网络·网络协议·tcp/ip
李白你好1 小时前
H3C网络设备(交换机、路由器、防火墙)常用命令整理
运维·网络·智能路由器
zhougl9962 小时前
Apache HttpClient 5 用法-Java调用http服务
java·http·apache
終不似少年遊*2 小时前
【从基础到模型网络】深度学习-语义分割-基础
网络·人工智能·深度学习·语义分割·卷积·上采样
卡戎-caryon2 小时前
【Linux网络与网络编程】12.NAT技术&&内网穿透&&代理服务
linux·运维·服务器·网络·网络协议·https
我的老子姓彭2 小时前
LWIP的Socket接口
运维·服务器·网络