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/postsposts#index显示所有帖子
GET/posts/newposts#new显示新建帖子的表单
POST/postsposts#create新建帖子
GET/posts/:idposts#show显示指定的帖子
GET/posts/:id/editposts#edit显示编辑帖子的表单
PATCH/PUT/posts/:idposts#update更新指定的帖子
DELETE/posts/:idposts#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-CredentialsAccess-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 端添加的头,不然重复添加会报错。
    • 另外,若支持所有域名,会有一些安全隐患,建议使用白名单。