目录
前言
HTTP Methods: Request methods define the type of action you are requesting to be performed.
GET
- Requests retrieve resource informationPOST
- The server creates a new entry in a databasePUT
- Updates an existing resourcePATCH
- Very similar to PUT but makes a partial update on a resourceDELETE
- Deletes resource or related componentHEAD
- Retrieve response headers identical to those of a GET request, but without the response body.CONNECT
- Establishes a tunnel to the server identified by the target resourceOPTIONS
- Describe the communication options for the target resourceTRACE
- Performs a message loop-back test along the path to the target resource<custom>
- Some APIs use custom request methods such as LIST. Type in your custom methods.
基本介绍
HTTP 方法是用于指示请求的类型的动作的标准化方式。以下是常见的 HTTP 方法:
- GET: 从服务器检索资源。通常用于获取数据。
- POST: 向服务器发送数据以创建资源。常用于提交表单或上传文件。
- PUT: 向服务器发送数据以更新资源。通常用于更新现有资源的全部内容。
- PATCH: 向服务器发送部分数据以更新资源。通常用于部分更新资源。
- DELETE: 从服务器删除资源。
- HEAD: 检索资源的头部信息,类似于 GET 请求,但不返回资源的主体部分。
- OPTIONS: 返回服务器支持的所有 HTTP 方法。
- CONNECT: 建立一个到目标资源的隧道。主要用于代理服务器。
- TRACE: 执行一个消息环回测试,沿着路径到目标资源的请求的路由。
示例代码
这里是一个简单的使用 fetch
函数执行几种常见 HTTP 方法(get、post、put、patch、delete)的示例代码:
async function httpRequest(method: string, url: string, data?: any) { const options: RequestInit = { method: method, headers: { 'Content-Type': 'application/json' }, body: data ? JSON.stringify(data) : undefined }; try { const response = await fetch(url, options); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); return result; } catch (error) { console.error('Error:', error); } } // 示例用法 const apiUrl = 'https://jsonplaceholder.typicode.com/posts'; // GET 请求 httpRequest('GET', apiUrl).then(data => console.log(data)); // POST 请求 httpRequest('POST', apiUrl, { title: 'foo', body: 'bar', userId: 1 }) .then(data => console.log(data)); // PUT 请求 httpRequest('PUT', `${apiUrl}/1`, { id: 1, title: 'foo', body: 'bar', userId: 1 }) .then(data => console.log(data)); // PATCH 请求 httpRequest('PATCH', `${apiUrl}/1`, { title: 'foo' }) .then(data => console.log(data)); // DELETE 请求 httpRequest('DELETE', `${apiUrl}/1`) .then(data => console.log(data));
说明
- httpRequest: 一个通用的 HTTP 请求函数,接受 HTTP 方法、URL 和可选的数据。
- RequestInit: 用于配置 fetch 请求的选项,包括方法、头部和主体。
- fetch: 执行 HTTP 请求的 JavaScript API。
这个示例演示了如何使用 fetch
函数执行各种 HTTP 方法的请求。你可以根据需要调整 url
和 data
参数以匹配你的具体 API。
具体介绍
前置知识:幂等和非幂等
幂等性(Idempotency)是计算机科学中的一个重要概念,用于描述操作的可重复性和稳定性。在 HTTP 请求中,幂等性表示多次执行相同的请求应当产生相同的结果。
幂等操作
定义: 幂等操作是指无论操作执行多少次,产生的效果都相同。
HTTP 方法的幂等性:
- GET: 幂等。多次执行 GET 请求会返回相同的资源数据,不会改变服务器状态。
- PUT: 幂等。多次执行 PUT 请求将资源替换为相同内容,因此效果相同。
- DELETE: 幂等。多次执行 DELETE 请求会删除资源,且删除不存在的资源不会再有变化。
- HEAD: 幂等。多次执行 HEAD 请求会返回相同的头部信息,不会改变服务器状态。
- OPTIONS: 幂等。多次执行 OPTIONS 请求会返回相同的支持方法列表,不会改变服务器状态。
- TRACE: 幂等。多次执行 TRACE 请求会返回相同的路径信息,不会改变服务器状态。
非幂等操作
定义: 非幂等操作是指操作执行多次会产生不同的效果。
HTTP 方法的非幂等性:
- POST: 非幂等。多次执行 POST 请求会创建多个资源,产生不同的结果。
- PATCH: 通常非幂等。多次执行 PATCH 请求可能会导致资源的部分更新,产生不同的结果。尽管有时可以设计成幂等,但一般认为是非幂等的。
幂等性和非幂等性的应用场景
幂等性应用场景:
- 数据读取: 使用 GET 方法读取数据,无论请求多少次,数据不会改变。
- 资源替换: 使用 PUT 方法完全替换资源,多次请求结果相同。
- 资源删除: 使用 DELETE 方法删除资源,多次请求结果一致。
非幂等性应用场景:
- 数据创建: 使用 POST 方法创建新资源,每次请求都会产生新的资源。
- 部分更新: 使用 PATCH 方法更新资源的部分内容,每次请求可能产生不同的结果。
总结
理解幂等性和非幂等性对于设计和实现可靠的 HTTP API 非常重要。幂等操作可以提高系统的稳定性和可预测性,而非幂等操作适合用于创建或部分更新资源。在实际开发中,选择合适的 HTTP 方法来满足业务需求,同时考虑幂等性,确保系统的健壮性和一致性。
1. GET
使用场景:
- 用于从服务器获取资源数据,如网页、图片、JSON 数据等。
- 适合只读取数据而不改变服务器状态的请求。
使用方法:
fetch('https://example.com/data') .then(response => response.json()) .then(data => console.log(data));
可能遇到的问题:
- 缓存问题:浏览器可能缓存 GET 请求的响应,导致获取的不是最新数据。可以通过设置请求头或在 URL 中添加时间戳来避免。
- URL 长度限制:有些浏览器对 URL 长度有限制,GET 请求参数太多时可能会出问题。
2. POST
使用场景:
- 用于向服务器发送数据以创建新资源,例如提交表单、上传文件等。
- 适合需要将数据发送到服务器进行处理的请求。
使用方法:
fetch('https://example.com/api', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'John', age: 30 }) }) .then(response => response.json()) .then(data => console.log(data));
可能遇到的问题:
- 重复提交:用户可能会多次点击提交按钮,导致重复提交。可以通过禁用按钮或其他方式避免。
- CSRF 攻击:需要防范跨站请求伪造攻击,通常通过使用 CSRF 令牌来防御。
3. PUT
使用场景:
- 用于更新服务器上的现有资源的全部内容。
- 适合需要完全替换资源的请求。
使用方法:
fetch('https://example.com/api/resource/1', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: 1, name: 'John', age: 31 }) }) .then(response => response.json()) .then(data => console.log(data));
可能遇到的问题:
- 幂等性:PUT 请求应当是幂等的,多次执行相同的 PUT 请求应当产生相同的结果。
- 数据完整性:需要确保发送的数据是完整的,因为 PUT 是替换整个资源。
4. PATCH
使用场景:
- 用于更新服务器上的资源的部分内容。
- 适合需要部分更新资源的请求。
使用方法:
fetch('https://example.com/api/resource/1', { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ age: 31 }) }) .then(response => response.json()) .then(data => console.log(data));
可能遇到的问题:
- 部分更新:确保只发送需要更新的字段,避免影响其他字段。
- 幂等性:虽然 PATCH 可以是非幂等的,但尽量使其幂等,即多次相同的 PATCH 请求应当产生相同的结果。
延伸:
要确保 PATCH 请求是幂等的,可以采取以下几种策略:
1. 确保操作是幂等的
在服务器端处理 PATCH 请求时,确保每次相同的请求对资源产生相同的修改效果。这通常涉及在更新资源时使用幂等的方法。
示例: 更新用户的某个属性
// PATCH 请求体 { "age": 31 }
服务器接收到这个请求时,只更新 age
属性,不改变其他属性。
2. 使用版本控制或条件更新
通过检查资源的版本或条件来确保更新操作的幂等性。例如,可以使用乐观锁定或 If-Match
头来进行条件更新。
示例:
PATCH /resource/1 HTTP/1.1 Host: example.com Content-Type: application/json If-Match: "abc123" { "age": 31 }
服务器只有在资源的版本匹配 If-Match
头中提供的版本时才会进行更新,这样可以确保幂等性。
3. 全量更新部分属性
尽量在 PATCH 请求中提供所有需要更新的字段,即使某些字段的值没有变化。这确保了每次请求都是对特定字段的完整更新,而不是依赖于资源的当前状态。
示例:
// PATCH 请求体 { "name": "John", "age": 31, "email": "john@example.com" }
4. 使用特定操作指令
在 PATCH 请求体中明确指定操作类型,如 replace
、add
、remove
等。这些操作可以使用 JSON Patch 格式来表示。
JSON Patch 示例:
[ { "op": "replace", "path": "/age", "value": 31 } ]
服务器根据操作指令执行相应的更新,从而确保幂等性。
5. 幂等标识符
使用幂等标识符来确保每个请求只被处理一次。客户端生成一个唯一的幂等标识符,并在请求中发送给服务器。服务器在处理请求时检查这个标识符,确保每个标识符只处理一次。
示例:
PATCH /resource/1 HTTP/1.1 Host: example.com Content-Type: application/json Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000 { "age": 31 }
示例代码
以下是一个简单的 Node.js 服务器示例,展示如何实现幂等的 PATCH 请求:
const express = require('express'); const app = express(); app.use(express.json()); let resource = { id: 1, name: 'John', age: 30, email: 'john@example.com' }; let processedRequests = {}; app.patch('/resource/:id', (req, res) => { const idempotencyKey = req.headers['idempotency-key']; if (idempotencyKey && processedRequests[idempotencyKey]) { return res.status(200).send(processedRequests[idempotencyKey]); } const update = req.body; // Update resource in an idempotent way if (update.name !== undefined) resource.name = update.name; if (update.age !== undefined) resource.age = update.age; if (update.email !== undefined) resource.email = update.email; const response = { message: 'Resource updated', resource }; if (idempotencyKey) { processedRequests[idempotencyKey] = response; } res.status(200).send(response); }); app.listen(3000, () => { console.log('Server running on port 3000'); });
总结
确保 PATCH 请求幂等性的方法包括:
- 确保操作是幂等的:每次相同的请求应产生相同的结果。
- 使用版本控制或条件更新:如
If-Match
头。 - 全量更新部分属性:确保所有需要更新的字段都包含在请求中。
- 使用特定操作指令:如 JSON Patch 格式。
- 使用幂等标识符:确保每个请求只处理一次。
通过这些方法,可以确保 PATCH 请求的幂等性,从而提高系统的可靠性和一致性。
5. DELETE
使用场景:
- 用于从服务器删除资源。
- 适合需要删除资源的请求。
使用方法:
fetch('https://example.com/api/resource/1', { method: 'DELETE' }) .then(response => { if (response.ok) { console.log('Resource deleted'); } });
可能遇到的问题:
- 幂等性:DELETE 请求应当是幂等的,多次执行相同的 DELETE 请求应当产生相同的结果。
- 资源不存在:需要处理删除不存在的资源的情况,通常返回 404 状态码。
6. HEAD
使用场景:
- 用于检索资源的元数据,而不获取资源的主体部分。
- 适合需要检查资源是否存在或获取资源的头部信息(如大小、类型)的请求。
使用方法:
fetch('https://example.com/data', { method: 'HEAD' }) .then(response => { if (response.ok) { console.log('Resource exists'); } });
可能遇到的问题:
- 信息有限:HEAD 请求只返回头部信息,不返回实际数据主体,需根据返回的头部信息判断资源状态。
7. OPTIONS
使用场景:
- 用于查询服务器支持的请求方法。
- 适合在跨域请求前检查服务器是否允许特定方法的请求。
使用方法:
fetch('https://example.com/api', { method: 'OPTIONS' }) .then(response => { if (response.ok) { console.log('Options:', response.headers.get('Allow')); } });
可能遇到的问题:
- 复杂请求:在跨域资源共享 (CORS) 中,复杂请求需要先发送 OPTIONS 请求,检查服务器是否允许请求方法。更具体的内容可以阅读 WHAT - http headers 介绍(含 CORS 配置)
8. CONNECT
使用场景:
- 用于建立到目标资源的隧道,主要用于代理服务器。
- 适合在需要通过代理进行安全连接(如 HTTPS)的请求。
使用方法:
CONNECT 方法通常由浏览器或其他客户端自动处理,用户不直接使用。
可能遇到的问题:
- 代理配置:确保代理服务器正确配置,以支持 CONNECT 方法。
9. TRACE
使用场景:
- 用于执行消息环回测试,诊断路径问题。
- 适合在开发和调试时检查请求的路径和中间代理的修改。
使用方法:
TRACE 方法通常由开发工具或诊断工具使用,用户不直接使用。
可能遇到的问题:
- 安全问题:TRACE 方法可能被滥用进行跨站脚本攻击(XSS),许多服务器默认禁用 TRACE 方法。
总结
每个 HTTP 方法都有其特定的使用场景和可能遇到的问题。根据需求选择合适的方法,并注意相应的安全性和幂等性,确保请求的正确性和可靠性。