Thinkjs学习笔记---REST API的跨域设置

in ThinkJS笔记 with 0 comments, 7667 views

最后选择了Thinkjs

用thinkjs也有一小段时间了,和其它国产框架一样,起初是处于观望态度。当然我最先的选择也不是thinkjs而是选的express,用到后面发现实现一个能让自己用着比较顺手的博客还是一件蛮困难或者说是繁琐的事情。远没有自己起初所想的那样简单,再次感叹一切贵在坚持...

express虽然足够简洁,不过想要重头开始实现一个相对完善的博客程序无疑是需要很大工作量的,想到马上过期的虚拟机,thinkjs这样更加全面和强大的mvc框架变成了我理想的选择,其中的诸多特性(灵活的路由,方便的MVC,完善的数据校验,面向未来的Es6/7支持,简洁的数据库CURD操作等等)足够自己使用了。

-- 。--~啰嗦了,回到正题,由于后台管理界面我选择了前后端分离的模式,而且分成了两块不同的构建项目(有点折腾,不过个人觉得两个搅和在一起作为一个项目进行构建会更让我头大哈哈,毕竟现在前端也变得复杂,有自己一套独立的构建工具流),自然也有了跨域的需求,好在官方文档有提供相对完善的配置说明,我用了以下设置:

this.header("Access-Control-Allow-Origin", this.header("origin") || "*");

似乎简单的一句就解决了跨域问题,得益于标准这确实解决了我们一些跨域场景需求。 上边提到的CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)

进一步的需求(支持跨域cookie)

跨域的同时我又遇到了需要给客户端cookie,CORS同样可以做到, 可以像下面这样:

this.header('Access-Control-Allow-Credentials',true);  // 在服务端设置

// 客户端同样设置,这里以Jquery为例(约定好规则 😅类似一个愿打一个愿挨)

// 跨域设置cokkie
$.ajax({
   url: a_cross_domain_url,
   xhrFields: {
      withCredentials: true
   }
});

还可以跨域设置cookie的需求我们也解决了。

进进一步的需求(支持REST API)

当我以为一切OK的时候,REST的DELETE和PUT请求却唱起了反调,这是要给好处费吗....因为用到了REST API,仅使用上边的设置还不能实现DELETE及PUT的跨域请求,表示我内心当时是崩溃的,折腾了两天,总算找到了问题所在,起先找的Thinkjs官网文档,有提供例子,不看还好,这一看彻底掉坑里了。

Thinkjs官网文档

// 如果是在 REST API,那么可以放在 __call 方法里判断,如:

export default class extends think.controller.base {
  __call(){
    let method = this.http.method.toLowerCase();
    if(method === "options"){
      this.setCorsHeader();
      this.end();
      return;
    }
    this.setCorsHeader();
    return super.__call();
  }
  setCorsHeader(){
    this.header("Access-Control-Allow-Origin", this.header("origin") || "*");
    this.header("Access-Control-Allow-Headers", "x-requested-with");
    this.header("Access-Control-Request-Method", "GET,POST,PUT,DELETE");
    this.header("Access-Control-Allow-Credentials", "true");
  }
}

爬出坑的设置

// 服务端代码
async __before() {
    this.header("Access-Control-Allow-Origin", this.header("origin") || "*");
    this.header("Access-Control-Allow-Headers", "x-requested-with");
    this.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
    this.header('Access-Control-Allow-Credentials',true);
    let method = this.http.method.toLowerCase();
    if(method === "options"){
      this.end();
      return;
    }
    let isLogin = await this.session('userInfo');
    if(!isLogin){
      this.fail('AUTH_FAILED');
    }
  }

this.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");

就是这家伙了,隐藏得比较深,不过本质不坏,就靠它干活。

回顾并梳理

REST请求可以分成两种,一种是简单请求,GET,POST及HEAD都算其中。另一种就是非简单请求,顾名思意它要复杂一些,按钮w3c规范它会先发一次预请求(Preflighted requests),去询问下服务器我能不能满足要求,满足的话会返回一系列CORS头信息设置,返回请求后客户端同样会验证,这两家伙表示彼此都不信任对方0。0,客户端会受浏览器的同源策略影响,因为相对GET POST HEAD请求,PUT DELETE请求安全性要求会更高些,验证更严格也是理所应当的。其中Orgin会自动被服务端获取,客户端可以不用配置,默认包含在请求头中发送,其它的设置基本都需要两两对应设置。

兼容性

现代浏览器均支持,IE10有完整实现,IE8 9需要通过 XDomainRequest 对象来实现CORS(¬_¬)。

图示

简单请求

简单请求

cokkie设置

cokkie设置

非简单请求(预请求+主请求)

非简单请求

综合

综合

**Tips:**想要更详细的了解可以查看底下列出的参考文档!不知觉中表示写的太多了点....

参考文档

HTTP访问控制(CORS)

Responses ${replyToWho} / Cancel Reply