您的位置:首页 > Web前端 > JavaScript

关于跨域和jsonp

2020-02-06 05:33 597 查看

关于跨域与jsonp:

1、跨域:当浏览器执行一个脚本的时候,都会检查是否同源,如果是同源才会执行这个脚本,如果不是的话就是跨越了。即不同域之间请求资源

举个例子:a.cn下面的js不能调用b.cn下面的js,已而为a.cn和b.cn是不同域的这种情况就称之为跨域。

同源:指的是相同的域名,端口相同,协议相同。

2、复习一下域名地址:

http://www.geogle:8080/script/juery.js

http://:协议号

www:子域名

geogle:主域名

8080:端口号

script/juery.js:请求地址

协议号、子域名、主域名、端口号任意一个不同都会引起跨域问题。

3、详谈json&jsonp

json是一种数据交换格式,而jsonp是一种数据交换的方法,也就是一种非官方跨域数据交互协议。

json:格式或者规则:<1>json只有两种数据类型描述符{}和[],:是映射符;,是分隔符;""定义符。

<2>{}用来描述一组不同类型的无序键值对组合,而[]用来描述一组相同数据类型的有序数据集合。

<3>字符串必须用双引号引起来,其他的不用。

// 描述一个人 var person = { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true } // 获取这个人的信息 var personAge = person.Age; // 描述几个人 var members = [ { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true }, { "Name": "John", "Age": 20, "Company": "Oracle", "Engineer": false }, { "Name": "Henry", "Age": 45, "Company": "Microsoft", "Engineer": false } ] // 读取其中John的公司名称 var johnsCompany = members[1].Company; // 描述一次会议 var conference = { "Conference": "Future Marketing", "Date": "2012-6-1", "Address": "Beijing", "Members": [ { "Name": "Bob", "Age": 32, "Company": "IBM", "Engineer": true }, { "Name": "John", "Age": 20, "Company": "Oracle", "Engineer": false }, { "Name": "Henry", "Age": 45, "Company": "Microsoft", "Engineer": false } ] } // 读取参会者Henry是否工程师 var henryIsAnEngineer = conference.Members[2].Engineer;

jsonp:产生:1、一个众所周知的问题就是ajax在请求没有访问权限的数据时,无论是什么请求动态页面还是静态页面,都一律不准的。2、但是又发现在web页面中调用js文件时不受跨域的影响,也就是说,带有src属性的标签都不受跨域影响例如:img srcipt iframe

3、现阶段,如果要通过纯web来跨域访问数据的话,就要在远程服务器上把数据装进js格式的文件中,以便于服务端进行处理和获取。4、这样的话解决方案就是web客户端与调用脚本一样的方式来获取跨域服务器上的js文件(一般以json结尾),也就是说,服务器之所以要动态的生成一个js文件,就是要把客户端的数据装进去,5、当客户端成功访问到js那个文件的时候,也就获取到了自己需要的数据,这个原理像是sjsx但是又不是。6、为了便于客户端使用数据,逐渐形成了一种非正式的 传输协议,叫做jsonp,这个协议的要点就是允许用户传递一个callback参数给服务器,服务器端再返回一个callback参数包裹着的json数据,这样客户端就可以随意的定义一些函数来处理已经获得的数据。

在这里实现一个用原生js用jsonp实现跨域请求数据和jquery封装好的jsonp形式的ajax实现跨域请求的数据。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script type="text/javascript"> // 得到航班信息查询结果后的回调函数 var flightHandler = function(data){ alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。'); }; // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码) var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler"; // 创建script标签,设置其属性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script标签加入head,此时调用开始 document.getElementsByTagName('head')[0].appendChild(script); </script> </head> <body> </body> </html>

解释:在这个的基础之上就是请求数据成功。上面这段代码就完美的验证了如何让服务器端知道它调用的是哪一个函数。这样写的原理就是在客户端上的js代码是动态生成的,在请求远程服务器端的时候告诉他我要xxx函数的js代码,我们可以看到url中传了一个node参数,就是告诉服务器我要的是CA1998航班的信息,我的回调函数是flightHandler.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Untitled Page</title> <script type="text/javascript" src=jquery.min.js"></script> <script type="text/javascript"> jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998", dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据 success: function(json){ alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。'); }, error: function(){ alert('fail'); } }); }); </script> </head> <body> </body> </html>

这里要注意的就是跨域请求只能是get请求不能是post请求。封装好的ajax会自动帮你生成回调函数并且把数据取出来供success属性使用。

jsonp和ajax的区别:

1.ajax和jsonp在调用技术上看起来很像,目的也是一样的,都是请求一个url然后把服务器返回的数据进行处理,所以jquery都是把jaonp作为ajax的一种形式进行封装。

2、但是其实他两是不同的东西,ajax的核心是通过XMLHttprequest获取非本页的内容,而jsonp是通过动态创建script

3、所以ajax和jsonp的区别不在于是否跨域,ajax也可以通过服务器进行跨域访问,而jsonp也同样不排斥对于同源数据的获取。

4、还有就是jsonp和ajax不一定都是要用json格式来传递数据,也可以用别的,但是这样就不利于jsonp提供公开服务。

4、通过iframe来跨子域,针对于子域不同而主域相同,类似于这样的:

http://a.study.cn/a.html 请求 http://b.study.cn/b.html

我们可以在这两个文件中加上document.domain="study.cn",然后再。a.html上写上iframe标签,去控制iframe上的contentDocument属性。domain也就是设置一个主域名。

在a.html:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

        <script type="text/javascript">

            document.domain = 'study.cn';

            function test() {

在这里操纵b.html

                alert(document.getElementById('a').contentWindow);

            }

        </script>

</head>

<body>

    <iframe id='a' src='http://b.study.cn/b.html' οnlοad='test()'>

</body>

</html>

在b.html:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>Insert title here</title>

<script type="text/javascript">

document.domain = 'study.cn';

</script>

</head>

<body>

    我是b.study.cn的body

</body>

</html>

如果你想用ajax来实现跨域的话,只有两种方法,一种是jsonp一种就是用iframe做一个代理。

该方法的问题所在:安全上来说的话就是当一个站点被攻击的时候另外一个也会受到影响,

如果一个页面中引入多个iframe要想控制所有的你只能设置的多个domain

解决跨域的几种方法:

1、jsonp

2、CORS:跨域资源共享。是一种允许当前域的资源被其他脚本所访问的机制。它允许浏览器向跨源服务器发送XMLHttpRequest请求,

简单介绍XMLHttpReqest:是一个浏览器的接口,使得js可以进行HTTP通信。

CORS通信是服务器自动完成的,与AJAX没有太大差别,因此只要服务器端实现了CORS接口,那么就可以实现跨域请求数据了。

浏览器将请求的方式分为两种请求,简单请求和非简单请求,同时满足一下两种要求的就是简单请求。只要有一种不满足,则是非简单请求。

(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

简单请求:对于简单请求来说,浏览器直接发出CORS请求,具体来说是在头信息中自动增加一个origin字段。如下

GET /cors HTTP/1.1 Origin: http://api.bob.com Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...

上面的头信息中,origin这个字段用来说明本次请求来自于哪个源,服务器根据这个值来决定是否同意这次请求。

如果origin指定的源不在许可范围内时,服务器会返回一个正常的HTTP回应,浏览器发现这个回应的头信息没有Access-Control-Allow-Origin 这个字段就知道出错了,从未抛出一个错误,被XMLHttpRequest的onerror捕获。

如果指定的源在许可范围的话,服务器返回的响应就会多几个字段头

Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Credentials: true Access-Control-Expose-Headers: FooBar Content-Type: text/html; charset=utf-8

上面的头信息中有三个与CORS有着重要联系:

第一个值:是必须的,它的值要么是请求origin的那个值,要么就是*,表示接受任何域名的请求

第二个值:可选它的值是一个布尔值,用于表示是否允许发送cookie,同意则为true不同意反之

第三个值:可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()属性只能拿到六个基本字段,如果要多加字段的话就重新写,像上面是要拿到FooBar字段。

withCredentials属性:如果在上面吧Access-Control-Allow-Credentials设置为true,那就要在创建XMLHttpRequest对象的时候价格withCredentials属性改为true,不然的话即便设为true也不会传递cookie.需要注意的是如果要发送cookie那么第一个值不能为*,cookie也是支持同源策略的。

非简单请求:是对服务器有特殊要求,比如请求类型是put或者delete或者contentype的字段类型是json或者application。非简单请求在通信之前会进行一次预检,

var url = 'http://api.alice.com/cors'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send();

上面的HTTP请求时put并且携带了一个自定义头信息,当浏览器收到这个请求时,判定这个请求时非简单请求,之后浏览器就会发送预检请求,服务器会返回:

OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...

服务器返回的方法是OPTIONS表示这个请求是用来询问的,头信息里的 关键字origin表示请求哪个源

除了头字段,预测返回的数据中还包括了两个重要字段,第一个:Access-control-Request-Method这个表示的是在进行通信的时候浏览器用的是那种方法。第二个:Acess-control-Rquest-Headers就表示的是浏览器在CORS请求的时候额外发送的字段。

服务器在收到预测请求后确认origin Access-control-Request-Method Acess-control-Rquest-Headers字段允许跨源请求。成功之后返回:HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain

里面包含Access-Control-Allow-Origin:表示http://api.bob.com可以请求数据。

CORS与JSONP的比较:CORS支持所有的请求,而jsonp只支持get 请求。jsonp的优势是在与支持老式机以及可以向支持CROS的服务器获取数据。

3、代理

这种方法是通过后台获取其他域名下的内容然后再把获取的内容返回到前端,这样就保证了在同一个域名下,就不存在跨域问题。

比如A(www.a.com/sever.php)和B(www.b.com/sever.php)各有一个服务器,A的后端直接访问B 的服务,然后把获取的响应值给前端,也就是A的服务在后台做了一个代理,只要访问A的服务器就相当于访问到了B的服务器。这种代理属于后台技术。

4、Window.name实现跨域

在同一个域中时可以采用跳转页面即window.location="b.html"来进行数据传递的

如果在不同的域,例如A页面要获取到B页面的数据,在B 页面中只需要写window.name=""等到A来获取,那么在A页面中我们是不能通过上面的方法来获取数据的,如何获取?在A的页面中使用iframe来充当一个中间人的角色,iframe的src写入的是B的页面地址,然后A要得到iframe得到的数据,就必须要获取到它的window.name,还必须要把iframe的src设置为A页面同一个域,不然就会违反同源策略。

5、H5引用的新方法window.postMessage适合用来跨子域。

如何写:window.postMessage(message,targinOrigin)

调用postMessage方法的window对象指的是要接受消息的那个window对象,该方法的第一个参数指的是要发送的消息,第二个参数用来限定接收消息的那个window对象所在的域,如果不想设定,可以采用通配符。

 

这里的postMessage就指的是接收消息的B,

  • 点赞
  • 收藏
  • 分享
  • 文章举报
XuQing_Y 发布了12 篇原创文章 · 获赞 5 · 访问量 531 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: