이번에는 Ajax의 크로스 도메인 문제를 해결하기 위해 Jsonp를 소개하겠습니다. Jsonp가 Ajax의 크로스 도메인 문제를 해결하는 데 사용할 수 있는 notes는 무엇입니까?
1. 소개
최근 크로스도메인 이슈가 많이 발생하는데, 우연히 이걸 보고 정리해봤습니다. JSONP에 관해서 바이두에는 정말 많은 것들이 있고, 많은 것들이 있습니다. 계속해서 따라하다 보면 사실 몇 가지 정보밖에 나오지 않을 텐데, 아직은 능력의 문제일 수도 있겠네요. 기본. 주목해야 할 점은 여기에서 Jsonp가 ajax의 도메인 간 문제를 해결하는 데 사용된다는 것입니다. 특정 구현은 실제로 ajax가 아닙니다.
1. 동일 출처 정책
브라우저에는 동일 출처 정책이라는 매우 중요한 개념이 있습니다. 소위 동일 출처란 도메인 이름, 프로토콜 및 포트가 동일함을 의미합니다. 서로 다른 소스의 클라이언트측 스크립트(JavaScript, ActionScript)는 명시적인 인증 없이는 서로의 리소스를 읽거나 쓸 수 없습니다.
2. JSONP
JSONP(JSON with Padding)는 주류 브라우저의 도메인 간 데이터 액세스 문제를 해결하는 데 사용할 수 있는 JSON의 "사용 모드"입니다. 일반적으로 동일 출처 정책으로 인해 server1.example.com에 위치한 웹 페이지는 HTML 스크립트 요소를 제외하고는 server1.example.com 이외의 서버와 통신할 수 없습니다. <script> 요소의 이러한 공개 정책을 사용하면 웹 페이지는 다른 소스에서 동적으로 생성된 JSON 데이터를 얻을 수 있으며 이러한 사용 패턴을 JSONP라고 합니다. JSONP로 캡처된 데이터는 JSON이 아니라 JSON 파서로 구문 분석하는 대신 JavaScript 인터프리터로 실행되는 임의의 JavaScript입니다. </script>
2. 연습
1. 도메인 간 요청 시뮬레이션
이 머신에서 Tomcat 두 개를 만드세요. 포트는 각각 8080과 8888이며 이는 원본이 아닌 원본 조건을 충족합니다. 하나에서 시작 포트가 다른 포트에서 데이터를 얻기 위해 ajax를 보내는 경우 크로스 도메인 요청 문제가 발생합니다.
여기에는 jsonp(8080)와 other(8888)라는 두 개의 프로젝트가 있습니다. jsonp 프로젝트의 index.jsp는 다음과 같습니다.
nbsp;html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <title>Insert title here</title> <script></script> <script> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } </script> <input>
다른(8888) 프로젝트의 index.jsp는 다음과 같습니다. 다음: // jsp가 실제로는 서블릿이기 때문에 여기서는 데모용으로 서블릿 대신 jsp를 사용합니다.
nbsp;html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <title>Insert title here</title> <script></script> other domain
사실 위에 보이는 것은 다른 페이지의 데이터를 가져오기 위해 jsonp 페이지에서 ajax 버튼을 클릭하는 것에 지나지 않습니다.
결과는 다음과 같습니다: chrome console
XMLHttpRequest가 http://localhost:8888/other/index.jsp를 로드할 수 없습니다. 요청한 리소스에 'Access-Control-Allow-Origin' 헤더가 없습니다. 따라서 원본 'http://localhost:8080'에는 액세스가 허용되지 않습니다.
위 팁은 8888 도메인의 리소스에 8080 도메인에서 액세스할 수 없다는 내용입니다.
2. 다른 도메인의 js 파일에 액세스하려면 script 태그를 사용하세요.
<script> 태그의 src는 도메인 간 요청을 지원합니다. 가장 일반적인 것은 CDN 서비스를 적용하는 것입니다. 예를 들어 제 프로젝트에서 jQuery를 사용하고 싶지만 그러한 js 파일이 없으면 다운로드하는 데 시간이 오래 걸리고, 잘 모르겠습니다. 버전이 정확하면 Baidu에서 jquery cdn을 검색할 수 있습니다. 예를 들어 bootstrap의 CDN(http://www.bootcdn.cn/jquery/) 중에서 선택할 수 있습니다. 프로젝트에 추가하세요. 가장 큰 단점은 인터넷에 연결되어 있지 않으면 그냥 가져오지 못한다는 것입니다. </script>
2.1 other의 루트 경로에 js/other.js 파일을 생성합니다. 내용은 다음과 같습니다.
alert("this is other(8888) js");
2.2 jsonp/index.jsp에 script 태그를 추가하고 other의 js를 소개합니다
<script></script>
http://localhost:8080/jsonp/index.jsp를 입력하면 가져온 js 파일이 자동으로 실행되고 도메인 간 js 요청이 성공했음을 나타내는 경고가 즉시 나타납니다.
2.3 마찬가지로 직접 인용은 즉시 알림을 실행한 다음 other.js에 함수를 작성하고 jsonp/index.jsp에서도 호출할 수 있습니다. 이것은 대부분 시연되지 않습니다. 개발이 완료되었으며 페이지가 js/css와 분리되었습니다.
2.4 另外说明一点,如果在other.js中有函数通过ajax调用8080中的东西,然后引入之后,调用这个函数,也是可以的,但是如果other.js中函数ajax调用8888的东西,引入之后,调用这个函数,同样是跨域的。
3、script实现跨域请求
3.1 简单模拟服务器返回数据
将jsonp/index.jsp改成如下:这里注意引入的other.js的位置,是在函数getResult之后的,如果在它之前的话,会提示函数不存在。js加载顺序是从上开始,在之前调用没创建的,不能成功。注意这里是指引入的js文件,如果是同一个js文件或者当前页面的js中,先执行调用,然后再写函数也是没有问题的,但是如果先执行调用引入js文件中的函数,然后再引入js文件,就会提示函数不存在。
<script></script> <script> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } function getResult(data){ alert(data.result); } </script> <script></script>
然后other.js
getResult({"result":"this is other domain's data"});
也就是在jsonp/index.jsp页面写好函数,然后引入其他域的js传入参数去调用这个函数,这里的参数你可以先看做是其他域服务器的接口返回的数据。
刷新页面,效果当然是
弹出alert框,this is other domain's data
3.2 模拟接口访问
看到这里,你会不会还是想不懂,上面js弄啥的,传个死的数据,有什么实际意义吗?,其实script的src不仅可以接js的地址,还可以接servlet的地址,也就是http接口地址,所以接下来,懒得写servlet,这里还是写jsp当做接口,在other项目中新建other.jsp页面,内容如下:
内容很简单,也就是接受一个params的参数,然后返回数据给调用者。
我们在jsonp/index.jsp中加上
<script></script>
看到这个地址,你是不是很熟悉,不熟悉的证明你用servlet用蠢了,jsp也是servlet,流程就是页面一加载的时候,script标签就会去发送请求,然后返回数据。那么我们刷新页面,看看效果。
Uncaught SyntaxError: Unexpected identifier
报错了,如上,然后代码有问题?No,点击错误,你会看到请求的东西也打印出来了,就是提示错误,表示这个东西浏览器不认识,其实是script不认识啦。
还不明白,那么你去页面加上如下内容,你看报不报错!!肯定报错
<script> ajax cross success,the server receive params : jsonp_param </script>
那么js不能解析,我们换一种思路,要是我们输出的是JSON字符串或者调用当前页面函数的字符串了,类似于3.1中返回的getResult({“result”:”this is other domain's data”});
所以改造一下,把other.jsp中的内容改成
别忘了,之前jsonp/index.jsp中我们定义了,那么加入引用之后,依然记得getResult函数与引入函数的先后顺序问题。
<script> function getResult(data){ alert(data.result); } </script> <script></script>
刷新页面,发现大工告成。
至此,大部分原理已经讲完了,还有一个问题,这里服务器返回的是getResult(xxx),其中这里的xxx可以当做是经过接口的很多处理,然后塞进去的值,但是这个getResult这个函数名,调用方与其他域服务器这一方怎么约定这个名字是一致的了,况且很多公司自己做服务的,别的公司的开发人员去调用,难道每个人都去那么公司去约定调用函数的名字?怎么可能,所以有人就想出来了一种解决方案,当然不是我~~,其实也很简单啦,也就是把回调的函数名字也一起传过去不就行了,所以代码如下:
<script></script>
other.jsp
代码很简单,也就是传递一个回调函数的参数名,然后经过该接口一系列操作,将返回数据,塞到回调函数里面,调用端的函数就得到了该接口的数据,也就是类似于ajax中succsss:function(data),然后处理data一样,这里的success回调函数,相当于上面的getResult函数。当然你也可以写的优雅一点,比如:
function CreateScript(src) { $("<script>/script>").attr("src", src).appendTo("body") } function jsonp_fun(){ CreateScript("http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult") }</script>
4、Jquery的JSONP
至此跨域请求的原理已经讲清楚了,但是仍然还有一个问题,总觉得这样用有点怪是不是,如果用jquery的话,调用就很简单了,其实jquery底层实现也是拼了一个script,然后指定src这种方式,跟上面讲的一样,只是jquery封装了一下,显得更加优雅,跟ajax调用方式差不多,所以容易记,代码如下:
<script> function getResult(data){ alert("through jsonp,receive data from other domain : "+data.result); } function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:"getResult",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以不写这个参数,jQuery会自动为你处理数据 success: function(data){ }, error: function(){ alert('fail'); } }); } </script> <input>
这里的jsonCallback,回调函数设置为getResult,那么返回后会先调用getResult函数中的代码,再调用success函数中的代码,一般情况下,不用定义getResult函数,同样jsonCallback不需要设置,那么就只执行success中的代码,也就跟平时的ajax一样用啦。
所以实际工作用法如下:
function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) success: function(data){ alert("through jsonp,receive data from other domain : "+data.result); }, error: function(){ alert('fail'); } }); }
这里没有指定jsonpCallback,实际上jquery底层拼装了一个函数名,当然生成函数规则就没研究了。
补充:
1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;
2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。</script>
3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。
4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 Jsonp는 Ajax의 도메인 간 문제를 해결합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!