ホームページ > 記事 > ウェブフロントエンド > Jsonp は ajax のクロスドメイン問題を解決します
今回は、ajax のクロスドメイン問題を解決するための Jsonp について説明します。Jsonp が ajax のクロスドメイン問題を解決するために使用できる notes について、実際のケースを見てみましょう。
1. はじめに
最近クロスドメインの問題が多く、たまたまこれを見かけたのでまとめてみました。JSONP に関しては、Baidu には本当にたくさんのものがあり、たくさんあります。これが続くと、実際にはほんの少しの情報しか見つかりませんが、それは私が何度も試した結果、最終的に理解できたものである可能性があります。基礎。注意すべき点は、ここでは、ajax のクロスドメイン問題を解決するために Jsonp が使用されているということです。実際の実装は、実際には ajax ではありません。
1. 同一生成元ポリシー
ブラウザには、同一生成元ポリシーという非常に重要な概念があります。いわゆる同一オリジンとは、ドメイン名、プロトコル、ポートが同じであることを意味します。異なるソースからのクライアント側スクリプト (JavaScript、ActionScript) は、明示的な承認がなければ、相互にリソースを読み書きすることはできません。
2. JSONP
JSONP (JSON with Padding) は、主流のブラウザーによるクロスドメイン データ アクセスの問題を解決するために使用できる JSON の「使用モード」です。同一生成元ポリシーにより、一般に、server1.example.com にある Web ページは、HTML スクリプト要素を除いて、server1.example.com 以外のサーバーと通信できません。 <script> 要素のこのオープン ポリシーを使用すると、Web ページは他のソースから動的に生成された JSON データを取得できます。この使用パターンは JSONP と呼ばれます。 JSONP でキャプチャされたデータは JSON ではなく、JSON パーサーで解析されるのではなく、JavaScript インタープリターで実行される任意の JavaScript です。 </script>
2. 練習してください
1. クロスドメインリクエストをシミュレートします
このマシン上で 2 つの Tomcat を作成します。ポートはそれぞれ 8080 と 8888 で、オリジナル以外のオリジンの条件を満たします。ポートが別のポートからデータを取得するために ajax を送信する場合、クロスドメイン要求の問題が確実に報告されます。
ここには jsonp (8080) と other (8888) という 2 つのプロジェクトがあります。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. script タグを使用して他のドメインの js ファイルにアクセスします
<script> タグの src はクロスドメインリクエストをサポートしています。最も一般的なのは CDN サービスのアプリケーションです。たとえば、私のプロジェクトで jQuery を使用したいが、そのような js ファイルがない場合、ダウンロードに時間がかかります。バージョンが正しい場合は、Baidu で jquery cdn を検索すると、ブートストラップの 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 同様に、直接引用するとすぐにalertが実行され、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 中国語 Web サイトの他の関連記事を参照してください。