请谈谈 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
相关推荐
葡萄学妹13 分钟前
CA证书(网络建设与运维)
网络
科技快报23 分钟前
中兴移动互联终端三剑齐发 AI、5G-A、WiFi7构建高效智能网络
网络·人工智能·5g
兴达易控23 分钟前
ProfibusDP主站转ModbusTCP网关如何进行数据互换
网络协议·profibus dp
Alfred young1 小时前
CS144 Lab Checkpoint 6: building an IP router
网络·tcp/ip·智能路由器
乄北城以北乀1 小时前
muduo库源码分析:TcpConnection 类
linux·数据结构·c++·后端·网络协议·tcp/ip·visual studio
GalaxyPokemon2 小时前
LINUX网络基础 [一] - 初识网络,理解网络协议
linux·运维·网络
alien爱吃蛋挞2 小时前
【JavaEE】网络原理
网络·java-ee
ling-453 小时前
ifconfig 不显示 Linux 虚拟机常规网卡的 IP 地址
服务器·网络·php
菜菜小蒙3 小时前
【Linux】http 协议
网络·网络协议·http