Node 解决跨域问题 JSONP与CORS

这里写图片描述

Node 解决跨域问题 JSONP与CORS

今天浅谈一下Node解决跨域的问题,其实跨域这个问题因为同源策略而一直存在的,是前端的必经之路,原来一直在用CORS,对于JSONP都忘的差不多,今天遇到一些小问题居然也懵了圈,以前也没有写过关于这方面的博文,所以今天特地拿出来写一下,希望能帮到大家。

CORS 与 JSONP的区别

CORS全称为跨域资源共享”(Cross-origin resource sharing),对于用了这么久的CORS的我来说,那感觉肯定是很爽了,相对于JSONP来也有很多好处,比如最大的一个看点就是,JSONP只能用GET请求来跨域,而使用了CORS之后,GET和POST都能用,并且还支持其他的HTTP METHOD,并且可以用Access-Control-Allow-Method进行筛选。

以前做一个小项目,为了使前后端分离,特地在测试期间,把后端使用CORS,这样前端在自己的本地服务器上测试的时候,若需要数据方面的测试也能方便的从后端获取。JSONP却达不到这样的效果,请求方法各式各样,不可能把精力都放在跨域的地方。

JSONP

为了使安全而出现的同源策略给我们带来了众多的好处,但是同时也限制了我们跨域获取资源,凡事都有正反两面,但同源策略的出现带给我们的总是利大于弊。 
JSONP就是在这种环境下出现的,它是一种非正式协议,使用JSONP跨域的方法大概是传给后端一个callback,后端收到后把,需要客户端需要的数据放到callback的参数列表中,这样客户端就能拿到了(这里的客户端一般是指服务器)。 
但是刚刚不是才说由于同源策略的限制而不能跨域么?对的,但是有几个标签是不受同源策略的约束的,比如img, iframe, script,我们大可将它们利用起来,帮助我们实现跨域。 
其实这里的callback并不是指的真正的回调函数,我们知道,回调函数是给调用者传入回调函数的函数指针,当调用者执行完毕后调用回调函数的回调指针,这就是一次回调,然而,JSONP只是传给后端一个回调函数名。

说了这么多,接下来来看一个小例子。 
在这个简单的html页面中,我们嵌入了script标签,它的src指向一个地址,这里的地址为请求后端的接口(这里为了方便演示直接请求到了根目录,总所周知,这是一种很不好的url设计),并附带一个callback的参数为getName,getName就是我们的回调函数名。这里会对后端发起一个GET请求。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script>
    function getName(data){
        console.log(data);
    }
    </script>
    <script src="http://localhost:9999?callback=getName"></script>
</body>
</html>

为了方便直接用Node作为后端了

const http = require('http');
const url = require("url");

http.createServer((req,res) => {
    let params = url.parse(req.url,true);
    if(params){
        res.end(params.query.callback + `(${JSON.stringify({name:"zhangsan"})})`);
        return;
    }
    res.end();
}).listen(9999,() => {
    console.log("listening");
});

if块中书写拿到queryParams之后的操作,这里的查询字符串就是上面客户端传来的callback。

 res.end(params.query.callback + `(${JSON.stringify({name:"zhangsan"})})`);

接着返回一个函数调用给客户端,实际上这里调用的就是客户端的getName()函数

启动服务器,客户端发起请求

这里写图片描述

如图所示已经拿到了数据。 
综上,就是一次简单的JSONP。

JQuery的JSONP

今天就死在这上面了,已经被MVVM,MVC,MVP洗脑的我,已经对JQ陌生,今天用JQ发送AJAX时,发现JQ可以用POST请求发起一次JSONP跨域,以前也没怎么注意。下面来一下JQuery是怎么发起一次跨域请求。

一个完整的JQ AJAX形如:

$.ajax({
    url:"http://localhost:9999",
    data:{name:"zhangsan"},
    type:"post",
    dataType:"jsonp",
    jsonp:"callback",
    jsonpCallback:"getName",
    async:true,
    timeout:5000,
    complete:function(){
        console.log("end");
    },
    success:function(data){
        console.log(data);
    },
    error:function(err){
        console.log(`have a error is ${JSON.stringify(err)}`);
    }
});

它与传统的AJAX并无两样,重点在于jsonp 和 jsonpCallback字段 
jsonp 用于指定传入后端的callback名称的参数名,如上面用script标签发起跨域请求时,参数名就为callback,默认情况下,jsonp字段为callback。这里写出来只是为了让大家知道存在这么个字段。 
jsonpCallback为需要传过去的回调函数名。但是这里并没有可以让我们调用的回调函数,这是因为jq的ajax使用jsonp时,获取到的数据已经作为参数传入success回调中,因此我们可以在success回调中拿到。

刷新页面,相同的结果! 
jsonp无疑是一种很nice的跨域解决方案。

CORS

跨域资源共享(Cross-origin resource sharing)机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。 
如果说jsonp是前端跨域的利剑,那CORS就是可以让前端徒手空拳跨域的Buff,它的配置也相当简单。 
重点就在于响应头,我们需要配置这么几个字段。

res.header("Access-Control-Allow-Origin","*");
res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept");  
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  

下面一个一个来看:

第一个响应头:

Access-Control-Allow-Origin

这是为了设置允许跨域的客户端请求地址 
第二个响应头:

res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept");  

响应首部 Access-Control-Allow-Headers 用于 preflight request(预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。

在一些非简单请求中,会发起一次预检请求,比如下面这些HTTP METHOD会发起一个预检请求,检查服务器是否同意此请求对服务器资源进行修改。

PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH

第三个响应头:

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

这是为了设置是否同意这些方法来修改服务器资源。

总结

跨域是web开发中必不可少的技术,虽然很简单,但是也不可忽视。

猜你喜欢

转载自blog.csdn.net/GoldenLegs/article/details/81662020