说说CORS与jsonp

栏目: Json · 发布时间: 6年前

内容简介:浏览器出于防止潜在安全风险的考虑,使用了同源策略,这一方面保证了我们数据的安全, 另一方面却又限制了我们的手脚,基于此,开发者们与标准制定组织提供了不同的解决方案, 这里主要说说CORS与jsonp。同源指的是两个域需要协议,子域名,主域名与端口号都保持一致,四者有一个不同,即属于跨域。CORS:跨域资源共享,是W3C制定的一个草案,定义了在必须访问跨源资源时,浏览器和服务器该怎么沟通。

浏览器出于防止潜在安全风险的考虑,使用了同源策略,这一方面保证了我们数据的安全, 另一方面却又限制了我们的手脚,基于此,开发者们与标准制定组织提供了不同的解决方案, 这里主要说说CORS与jsonp。

什么是同源策略

同源指的是两个域需要协议,子域名,主域名与端口号都保持一致,四者有一个不同,即属于跨域。 注意: http://localhost:8080与http://127.0.0.1:8080不属于同源,也就是说,即使IP地址一致,但是一个是域名,一个是IP地址,也不属于同源。

CORS的使用与注意点

CORS:跨域资源共享,是W3C制定的一个草案,定义了在必须访问跨源资源时,浏览器和服务器该怎么沟通。

CORS的实现原理是,浏览器发出请求报文中会额外包含一个Origin头部,该头部的值是当前页面的源信息(协议,域名和端口),服务器收到请求报文后,如果同意这个跨源请求,就在响应报文的头部添加Access-Control-Allow-Origin,值与请求报文中的Origin头部的值一致,如果响应报文中没有这个头部或者有,但是值不一致,这次的跨源请求就会失败。

浏览器原生支持CORS,但是不同的浏览器支持的方式不同。 IE8及以上版本引用了XDR(XDomainRequest)类型,这个对象和XHR对象类似,使用这个对象,可以实现安全可靠的跨域通信。 XDR的使用与XHR类似,使用过程如下:

  1. 实例化XDR
var xdr = new XDomainRequest();
复制代码
  1. 调用open(),open()接收两个参数,请求所用的方法以及URL,所有的XDR都是异步执行的,所有不需要第三个参数。
xdr.open('get','#');
复制代码
  1. 调用send(),如果使用的是get方法,传入null,如果是post方法,传入字符串。
xdr.send(null);
复制代码
  1. 为xdr绑定事件处理函数。xdr支持的事件包括load,error,timeout。 需要说明一点的是,这部分的事件监听器需要在调用open()之前声明,这里只是行文需要。 4.1 load事件 在接收到响应后,你可以访问响应的原始文本,但是没有办法确定响应的状态码,只有在响应有效的/情况下才会触发load事件,如果接收到的响应中不包含Access-Control-Allow-Origin头部的话,则会触发error事件。
xdr.onload=function(){
  console.log(xdr.resonseText);
}
复制代码

4.2 error事件导致XDR请求失败的因素很多,所有为每个xdr对象绑定该事件的处理函数是很有必要的,但是该事件抛出的信息有限,我们只能确定请求失败了,并不能得知请求失败的原因。

xdr.onerror=function(){
  console.log('get a error');
}
复制代码

4.3 timeout事件xdr对象有一个timeout属性,该属性表明请求自发出多久后超时,当为其赋值后,在给定的时间内还没接受到响应,就会触发timeout事件。

xdr.ontimeout=function(){
  alert('time is too long');
}
复制代码

使用XDR需要注意的点:

  1. cookie不会随请求发送,也不会随请求返回。
  2. 不能访问响应头部信息,这意味着xdr对象没有getResponseHeader()和getAllResponseHeaders()。
  3. 只支持get和post方法。
  4. 当使用post方法时,xdr对象有一个contentType属性,这个属性可以表示要发送的数据的格式,这是xdr对象能够影响头部信息的唯一方法。

其他浏览器对CORS的实现其他主流浏览器通过XHR对象原生支持CORS,在尝试打开不同来源的资源时,XML可以自动触发这个行为,有一点不同的是,open方法中的URL参数需要传入绝对路径。

使用XHR对象进行跨域通信的注意点:

  1. 不能使用setRequestHeader()设置自定义头部。
  2. 不能发送和接收cookie。
  3. 调用getAllResponseHeaders()返回空字符串,调用getResponseHeader()报错。
  4. 由于同源请求和跨源请求都使用同样的接口,因此对于本地资源,使用相对URL,对跨源的资源,使用绝对路径,这样可以避免跨源请求时的限制(见1,2)。

这个给出一个例子,本地文件是index.html,服务端文件为server.js,需要注意的是,我们需要使用http-server(其他的也可以)搭建一个静态资源服务器,关于http-server的使用,点击这里,这样可以使用http协议访问index.html文件,使用file协议无法使用CORS。

// index.html
<script>
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange=(req,res)=>{
            if(xhr.readyState==4){
                if((xhr.status>=200&& xhr.status<300)||xhr.status==304) {
                    console.log(xhr.responseText);
                    console.log(xhr.getResponseHeader('Connection'));
                } else {
                    console.log('Request was unsuccessful: '+xhr.statusText);
                }
            }
        };
        xhr.open('get','http://127.0.0.1:3000/',true);
        xhr.send(null);
</script>
复制代码
//server.js
const express = require("express");  //记得安装express

const app = express();

app.get("/", function (req, res) {
    res.setHeader('Access-Control-Allow-Origin','http://localhost:8080');
    res.end('hello world!');
});

app.listen(3000, function () {
    console.log("app is listening 3000");
});
复制代码

CORS的高级使用技巧

CORS支持在跨域请求的过程中,使用自定义的头部信息,post和GET之外的方法,不同类型的主体内容和提高凭据(cookie)。在使用这些高级选项发送请求时,浏览器会首先发送一个Prefight请求,这种请求使用options方法,这是一种透明的服务器验证机制,开发者不需要做这些。 该请求这需要包含以下的头部:

  1. Origin:与简单的请求相同。
  2. Access-Control-Allow-Method:请求自身使用的方法(是指我们主动发起的跨域请求的方法,不是options)。
  3. Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部已逗号隔开。 除了这些头部信息外,xhr有withCredentials属性,将该属性设置未true,可以在请求过程中携带cookie。

服务器在接收到这个请求后,如果同意这次跨域请求,就会在响应中设置响应的头部信息。 这些头部信息包括:

  1. Access-Control-Allow-Origin:与简单的请求相同。
  2. Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔。
  3. Access-Control-Allow-Headers:允许的头部,多个头部以逗号隔开。
  4. Access-Control-Max-Age:应该将这个Preflight请求缓存多长事件(以秒表示)。 5.Access-Control-Allow-Credentials:布尔值。

这里给一个完整的例子:

//index.html
<script>
      var xhr = new XMLHttpRequest();
      document.cookie = "name=wang";  //BOM提供的接口,用于设置当前页面所在的域的cookie
      xhr.withCredentials = true;  //允许在这次请求中携带cookie
      xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
          if ((xhr.status >= 200) & (xhr.status < 300) || xhr.status == 304) {
            console.log(xhr.responseText);
            console.log('name:'+xhr.getResponseHeader("name"));
          } else {
            console.log("Request was unsuccessful: " + xhr.status);
          }
        }
      };
      xhr.open("PUT", "http://localhost:4000/getData", true);  //使用put方法
      xhr.setRequestHeader("age", 12);  
      xhr.send(null);
    </script>
复制代码
//server1.js
//将该文件与index.html放在一个目录下
const Koa = require('koa');
const app = new Koa();
const server = require('koa-static');
const home = server(__dirname);
app.use(home);
app.listen(3000,()=>{
    console.log('app is runnint at port 3000');
})
//运行该代码后,可以在http://localhost:3000/index.html访问到index.html。
复制代码
//server2.js
const Koa = require('koa');
const router = require('koa-router')();
const app = new Koa();

app.use(async (ctx, next) => {
    console.log(`Process ${ctx.request.method}: ${ctx.request.url}`)
   await next();
})


app.use(async (ctx, next) => {
    ctx.response.set('Access-Control-Allow-Origin', 'http://localhost:3000');
    ctx.response.set('Access-Control-Allow-Headers', "age");
    ctx.response.set('Access-Control-Allow-Methods', "PUT");
    ctx.response.set('Access-Control-Allow-Credentials', true);
    ctx.response.set('Access-Control-Allow-Max-Age', 6);
    ctx.response.set('Access-Control-Expose-Headers', 'name');
    if (ctx.method === 'OPTIONS') {
        ctx.body = 'OPTIONS';
    };
    await next();
})

router.put('/getDate',async (ctx,next)=>{
    console.log(ctx.request.header.age);
    ctx.response.set('name','wang');
    ctx.body='put';
    await next();
})
app.use(router.routes());

app.listen(5000, () => {
    console.log('app is listening at port 5000');
});
复制代码

运行以上server1.js,server2.js文件,访问http://localhost:3000/index.html。

说说CORS与jsonp
说说CORS与jsonp

从以上的图片中,可以看到,在进行跨域请求时,携带了cookie,并且浏览器在后台替我们发送了一个options方法的请求。 **总结:**CORS的高级用法其实就是在真正与服务器进行跨域通信时,浏览器会先发送一个options方法的请求,帮我们跟服务器进行‘沟通’,基于沟通结果,决定我们真正需要的跨域通信的成功或失败。

###jsonp

jsonp利用script标签可以不受限制的从其他域加载资源的能力,进行跨域通信。jsonp由两部分组成: 回调函数数据 。回调函数是响应带来时,应该调用的函数,它需要在URL中指定;数据就是服务器返回给浏览器的响应。

jsonp的使用:

  1. 创建一个script元素。
  2. 声明一个回调函数。
  3. 为script指定src属性的值,需要将回调函数作为URL的查询字符串,形式为:'callback=functionName' 这里给出一个完整的例子
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
    <script>
        var script = document.createElement('script');
      //回调函数
        var blog = function(str){
          console.log(str);
        }
        script.src='http://localhost:3000/?callback=blog';
        document.body.appendChild(script);
        </script>
</body>
</html>
复制代码
//server.js
const Koa = require('koa');
const app = new Koa();
const router = require('koa-router')();

router.get('/',async(ctx,next)=>{
    var name = ctx.request.querystring.split('=')[1];
    console.log(name);
    var value='hello world!';
    ctx.body = `${name}('${value}')`;
})

app.use(router.routes());

app.listen(3000,()=>{
    console.log('app is running at port 3000');
})
复制代码

其实jsonp的内在逻辑很简单,在script标签中声明的函数是属于全局的,当服务器返回字符串后,这个字符串会被当做JavaScript代码执行,也就是调用之前声明的函数。 ##总结 CORS属于浏览器原生支持,支持所有类型的HTTP请求,是跨域通信的根本解决方案。 jsonp是开发者们为了绕开同源策略的权宜之计,虽然只支持get方法,但是使用简单。

总结

CORS属于浏览器原生支持,支持所有类型的HTTP请求,是跨域通信的根本解决方案。 jsonp是开发者们为了绕开同源策略的权宜之计,虽然只支持get方法,但是使用简单。

参考


以上所述就是小编给大家介绍的《说说CORS与jsonp》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Letting Go of the Words

Letting Go of the Words

Janice (Ginny) Redish / Morgan Kaufmann / 2007-06-11 / USD 49.95

"Redish has done her homework and created a thorough overview of the issues in writing for the Web. Ironically, I must recommend that you read her every word so that you can find out why your customer......一起来看看 《Letting Go of the Words》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试