RestfulAPI和GraphQL

RESTful API 和 GraphQL 是两种对立的 API 设计范式 ,restfulapi的哲学是一切皆资源,用url标识资源

/users          → 用户集合
/users/123      → 单个用户
/users/123/posts → 用户的文章

介绍

在restfulapi中,http方法表意动词操作资源,比如GET方法读取 GET /user/123,POST创建,POST /users,PUT表全量更新 PATCH部分更新 DELETE删除。

方法 + URL = 完整语义。DELETE /users/123 一看就知道"删除 123 号用户"。每个请求都是独立的,服务端不会保存客户端状态,有统一接口,状态码表意。

REST好用是好用,也有几个缺点,一个是过渡获取,客户端要的字段少服务器返回一堆,比如你可能只要name,但是一次性拿到的是全部(其实和这个要后端端点的设计),一个页面需要多个资源可能要多个请求。后端要版本管理,加字段可能破坏兼容性。

GraphQL核心思想是描述客户端需求之后服务端再返回这些。只需要单一端点,客户端指定好字段就行:

POST /graphql

query {
    user(id: 123) {
        name
        posts {
            title
        }
    }
}

直接返回
{
    "data": {
        "user": {
            "name": "Alice",
            "posts": [
                { "title": "文章 1" },
                { "title": "文章 2" }
            ]
        }
    }
}

缺点是缓存复杂,rest可以用HTTP天然缓存,GRAPHQL要客户端缓存,查询有复杂度,嵌套查询可能触发大量数据库查询。

除此外,还有好几种其他的: gRPC、tRPC、WS、SOAP。

options请求

在 RESTful API 中,OPTIONS 请求主要用于协商跨域资源共享和查询资源支持的 HTTP 方法。它本身不修改资源,属于“安全”和“幂等”的方法。

在非简单的请求前,浏览器会先发送OPTIONS请求去询问浏览器是否允许,比如触发场景是跨域+非简单请求,这个操作叫做CORS预检请求。

除此以外,OPTIONS会参与到了查询Allows头,客户端询问某个资源支持哪些HTTP方法,在手动调用或者工具探测的时候会发生。还有API能力发现,获取资源的原信息,支持的格式等。

我们最常用的请求叫做简单请求,就比如GET HEAD POST,请求头只包含:Accept、Accept-Language、Content-Language、Content-Type(且值只能是 application/x-www-form-urlencoded、multipart/form-data、text/plain)

非简单请求会触发OPTIONS,比如PUT DELETE PATCH CONNECT TRACE OPTIONS本身。 或 POST 但 Content-Type 是 application/json或带有自定义请求头(如 Authorization、X-Custom-Header)

那么这个说完了我们来看看浏览器在CORS预检中的请求是什么样子:

OPTIONS /api/users/1 HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization

当浏览器发送了这个请求之后,可能返回的就是:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

记住,浏览器会返回允许的源、允许的方法、允许的请求头、还有预检结果缓存时间,期间内不再重复预检。

安全性和幂等性

作为一个前端开发,我们有必要记忆清楚每个方法的安全性和幂等性:

方法用途安全幂等典型状态码
GET获取资源✅✅200
POST创建资源❌❌201
PUT全量替换资源❌✅200 / 204
PATCH部分更新资源❌✅200 / 204
DELETE删除资源❌✅204
HEAD获取响应头(无 body)✅✅200
OPTIONS查询支持的方法 / CORS 预检✅✅204
安全表示不修改资源,只读。幂等表示执行一次和多次请求的效果是相同的。POST 既不安全也不幂等,这是它和其他方法最大的区别。 PUT 是幂等的,多次 PUT 同一个资源,结果一样。

状态码

记住分组含义:

分组含义常见
1xx信息很少用
2xx成功200、201、204
3xx重定向301、302、304
4xx客户端错误400、401、403、404、405、429
5xx服务端错误500、502、503

高频状态码:

状态码含义易错点
200成功通用
201已创建POST 创建资源后返回,通常带 Location 头
204无内容DELETE、PUT 成功后返回,无 body
301永久重定向资源永久换了 URL
302临时重定向资源临时换了 URL
304未修改缓存命中,客户端用本地缓存
400请求错误参数格式错、缺少字段
401未认证没登录,或 token 无效
403无权限登录了,但没权限访问
404未找到资源不存在
405方法不允许URL 存在,但不支持这个方法
429请求过多限流
500服务器内部错误代码异常
502网关错误上游服务挂了
503服务不可用服务维护或过载

内容协商和其他分类

客户端和服务端通过 HTTP 头协商数据格式:

请求头作用
Accept客户端想要什么格式,如 application/json
Content-Type请求体的格式,如 application/json
Accept-Language想要什么语言
Accept-Encoding想要什么压缩格式
ACCEPT是客户端向服务端发送自己想要的数据格式,Content-Type是发送方告诉接收方它发的数据是什么格式,如果服务端返回406,就表示Not Acceptable,无法满足Accept。

CORS相关的有很多的头,跨域的时候服务端需要返回这些头:

响应头作用
Access-Control-Allow-Origin允许的源
Access-Control-Allow-Methods允许的方法
Access-Control-Allow-Headers允许的请求头
Access-Control-Allow-Credentials是否允许携带 cookie
Access-Control-Max-Age预检结果缓存时间
Access-Control-Expose-Headers客户端能读取的响应头
请求头也用来认证和授权,比如我们常见的Bearer Token,Authorization: Bearer <token>,最常用。或者API KEY:X-API-Key: <key> 等。

其他的还有缓存控制、条件请求、范围请求、代理转发、连接管理、安全、追踪,这个我先不讲,HTTP笔记我会细讲。