REST接口规范及跨域解决方案
April 27, 2021
Tag: [ Dev, Frontend ]
...本文为5、6年前的公司技术分享。 可能部分文字缺少解说,请自行脑补。 对于前端应对 CORS 和实用 Nginx 等,会单独写文说说。
介绍
REST与SOAP的区别
- SOAP (Simple Object Access Protocol): 简单对象访问协议
- REST (Representational State Transfer): 表述性状态传递
- 是设计风格而不是标准
- 关键: 通过传输数据含状态(state),达到客户端与服务器的无状态(stateless)
URI(统一资源标识符) 与URL(统一资源定位符)的区别
- URI (Uniform Resource Identifier): 统一资源标识符
- URL (Uniform Resource Locator): 统一资源定位符
- URL 是 URI 的子集
CRUD == 生见变灭
特性
- 幂等
- 无状态
- session -> token
- remember me
- 分布式
约定俗成
HTTP 方法 | 路径 | 控制器#动作 | 作用 |
---|---|---|---|
GET | /posts | posts#index | 显示所有帖子 |
GET | /posts/new | posts#new | 显示新建帖子的表单 |
POST | /posts | posts#create | 新建帖子 |
GET | /posts/:id | posts#show | 显示指定的帖子 |
GET | /posts/:id/edit | posts#edit | 显示编辑帖子的表单 |
PATCH/PUT | /posts/:id | posts#update | 更新指定的帖子 |
DELETE | /posts/:id | posts#destroy | 删除指定的帖子 |
Ajax & 跨域
需要鉴权的 Ajax 请求时需带上withCredentials
参数,例:
$.ajax({
url: 'http://foo.com/posts',
xhrFields: {
withCredentials: true
}
});
例中为 jQuery。
若是 zepto,可用beforeSend: function(xhr) { xhr.withCredentials = true; }
Nginx配置
add_header Access-Control-Allow-Origin *;
与 webview 客户端 cookie 互通:
add_header Access-Control-Allow-Origin http://foo.com;
add_header Access-Control-Allow-Credentials true;
注意上面的代码,使用Access-Control-Allow-Credentials
时Access-Control-Allow-Origin
不能使用通配符。这时会遇到另一个问题,有时需要允许多个域名访问,而直接添加多个域名是不生效的(多行,逗号分隔,空格分隔都不行),此时可以改为:
if ($http_origin ~ "^(http://foo.com|http://bar.com)$") {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
}
前端在开发过程中的跨域解决
跨域包括简单
和preflight
两种。
- 简单请求: 对 METHOD, HEADER, Content-Type 等有限制 详情
preflight
会先发OPTIONS
请求,通过后才会进行真正的请求
当前端本地开发,远程连后台,而某些后台不支持跨域时, 有几种方案:
方案1: 通过浏览器插件或者设置(
--disable-web-security
),关闭 CORS 安全校验。(个人不推荐)- 优点: 最简单
- 缺点: 不安全、不优雅、有时会导致其他诡异问题
方案2:Nginx 转发
OPTIONS
请求(安利本地装 Nginx,以后仔细说说)。如:
if ($request_method = OPTIONS ) {
add_header Content-Length 0;
add_header Content-Type text/plain;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Accept, X-Requested-With, Session';
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
return 200;
}
- 方案3:修改服务器代码,支持。(一般没戏)
- 注意,若代码端自动添加头,需要删除 Nginx 端添加的头,不然重复添加会报错。
- 另外,若支持所有域名,会有一些安全隐患,建议使用白名单。