四维视界 fancyoung

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-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 端添加的头,不然重复添加会报错。
    • 另外,若支持所有域名,会有一些安全隐患,建议使用白名单。

© 2025, Built with @思扬