针对ajax跨域问题,nodejs解决方案

2018-07-16
JavaScript
3526

ajax跨域的原理

首先需要明确的是只有ajax请求才会出现跨域,像<script src>这类请求,并不存在跨域问题。 ajax出现请求跨域错误问题,主要原因就是因为浏览器的“同源策略”,可以参考

浏览器同源政策及其规避方法(阮一峰)

CORS请求原理

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

基本上目前所有的浏览器都实现了CORS标准,其实目前几乎所有的浏览器ajax请求都是基于CORS机制的,只不过可能平时前端开发人员并不关心而已(所以说其实现在CORS解决方案主要是考虑后台该如何实现的问题)。

关于CORS,强烈推荐阅读 跨域资源共享 CORS 详解(阮一峰)

另外,这里也整理了一个实现原理图(简化版):

6bb9df09-b320-4e72-99cc-924434dfda6b

如何判断是否是简单请求?

浏览器将CORS请求分成两类: 简单请求 (simple request)和 非简单请求 (not-so-simple request)。 只要同时满足以下两大条件,就属于简单请求。

  1. 请求方法是以下三种方法之一:HEAD,GET,POST
  2. HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type(只限于三个值application/x-www-form-urlencoded、 multipart/form-data、text/plain)

凡是不同时满足上面两个条件,就属于非简单请求。

如何解决ajax跨域

JSONP方式解决跨域问题

jsonp解决跨域问题是一个比较古老的方案(实际中不推荐使用),这里做简单介绍(实际项目中如果要使用JSONP,一般会使用JQ等对JSONP进行了封装的类库来进行ajax请求)

实现原理 JSONP之所以能够用来解决跨域方案,主要是因为 <script> 脚本拥有跨域能力,而JSONP正是利用这一点来实现。具体原理如图

e9a52944-74e8-43dd-af6e-5bdc7aeb0744

实现流程

function addScriptTag(src) {
  var script = document.createElement('script');
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo');
}

function foo(data) {
  console.log('response data: ' + JSON.stringify(data));
};                      

请求时,接口地址是作为构建出的脚本标签的src的,这样,当脚本标签构建出来时,最终的src是接口返回的内容 浏览器返回

foo({
  "test": "testData"
});    

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

实际应用 前端代码

$.ajax({
    url: url,
    method: 'get',
    dataType: 'jsonp',
    success: function () {}
);

node(express) 代码 express 只需要使用resjsonp方法,将返回对象发给客户端即可。

app.use(PATH, (req, res) => {
    var reponseData = {a: 'aaa'};
    res.jsonp(responseData);
})

CORS解决跨域问题

Node.js后台配置(express框架)

app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By", ' 3.2.1')
        //这段仅仅为了方便返回json而已
    res.header("Content-Type", "application/json;charset=utf-8");
    if(req.method == 'OPTIONS') {
        //让options请求快速返回
        res.sendStatus(200); 
    } else { 
        next(); 
    }
});

前端代码

$.ajax({
        url: url,
        method: 'post',
        success: function (res) {
            console.log(res);
        }
    })

由于后端设置了cors设置,前端就可以像请求本地资源一样请求资源,非常方便。

总结

ajax 跨域问题,不推荐使用jsonp,而是后端服务做响应的配置,前端直接调用。

参考文档

https://segmentfault.com/a/1190000012469713