Home > Article > Web Front-end > Jsonp solves the cross-domain problem of ajax
This time I will bring you Jsonp to solve the cross-domain problem of ajax. What are the precautions for Jsonp to solve the cross-domain problem of ajax. The following is a practical case, let's take a look.
1. Introduction
There have been a lot of cross-domain issues recently, and I happened to see this one, so I summarized it, about JSONP There are indeed a lot of things on Baidu, and many people copy others. If this continues, I can actually find only a few pieces of information. The key is that I still can’t understand it. It may be a matter of ability. After many attempts, I have summarized it. After a while, I finally figured it out. One thing to note is that Jsonp is used here to solve the cross-domain problem of ajax. The specific implementation is not actually ajax.
1. Same-Origin Policy
Browsers have a very important concept - Same-Origin Policy. The so-called same origin means that the domain name, protocol and port are the same. Client-side scripts (JavaScript, ActionScript) from different sources cannot read or write each other's resources without explicit authorization.
2. JSONP
JSONP (JSON with Padding) is a "usage mode" of JSON that can be used to solve the problem of cross-domain data access by mainstream browsers . Due to the same-origin policy, generally speaking, web pages located at server1.example.com cannot communicate with servers other than server1.example.com, with the exception of the HTML script element. Using this open policy of the <script> element, web pages can obtain JSON data dynamically generated from other sources, and this usage pattern is called JSONP. The data captured with JSONP is not JSON, but arbitrary JavaScript, which is executed with a JavaScript interpreter instead of parsed with a JSON parser. </script>
2. Practice
1. Simulate cross-domain requests
Make two on this machine There is a tomcat, and the ports are 8080 and 8888 respectively, which meets the condition of non-same origin. If you send ajax from one port to obtain data from another port, a cross-domain request problem will definitely be reported.
There are two projects here, namely jsonp (8080) and other (8888). The index.jsp in the jsonp project is as follows:
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>
other (8888) The index.jsp in the project is as follows: // Because jsp is actually a servlet, jsp is used here instead of servlet for demonstration.
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
In fact, the above view is nothing more than clicking the ajax button on the jsonp page to obtain the data in other pages.
The results are as follows: chrome console
##XMLHttpRequest cannot load http://localhost:8888/other/index.jsp. No 'Access-Control- Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.The above tips refer to cross-domain issues. You cannot access 8888 from the 8080 domain. domain resources.2. Use the script tag to access js files in other domains
Because the src of the <script> tag supports cross-domain requests. The most common one is the application of CDN services. For example, in my project, if I want to use jQuery, but there is no js file, it will take a long time to download it, and I don’t know if the version is correct, then I can search jquery cdn on Baidu. I can find one at random, such as bootstrap's CDN: http://www.bootcdn.cn/jquery/. There are many versions for you to choose from. Just add it to the project. The biggest disadvantage is that if you don't have an Internet connection, just import it. It’s not coming. <p style="text-align: left;"><p style="text-align: left;">2.1 Create the js/other.js file in the other root path. <strong>The content is as follows: <pre class="brush:php;toolbar:false">alert("this is other(8888) js");<p style="text-align: left;">2.2 In jsonp/index.jsp, add the script tag , import other's js<strong><pre class="brush:php;toolbar:false"><script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script> into http://localhost:8080/jsonp/index.jsp, an alert will pop up immediately, indicating that the imported js file is automatically executed, and the cross-domain request for js is successful. <p style="text-align: left;"></p> <p style="text-align: left;"><img title="" alt="Jsonp solves the cross-domain problem of ajax" src="https://img.php.cn/upload/article/000/061/021/6aa998e4d2edca235a11c4aef7eb7a24-2.png"></p> <p style="text-align: left;">2.3 Similarly, if you quote directly, the alert<strong> will be executed immediately, then write the function in other.js, the same as jsonp/index.jsp It can also be called in , but I won’t demonstrate this point. This is mostly done in project development, and the page is separated from js/css. </strong></p> <p style="text-align: left;"><strong>2.4 另外说明一点,</strong>如果在other.js中有函数通过ajax调用8080中的东西,然后引入之后,调用这个函数,也是可以的,但是如果other.js中函数ajax调用8888的东西,引入之后,调用这个函数,同样是跨域的。</p> <p style="text-align: left;"><strong>3、script实现跨域请求</strong></p> <p style="text-align: left;"><strong>3.1 简单模拟服务器返回数据</strong></p> <p style="text-align: left;">将jsonp/index.jsp改成如下:这里注意引入的other.js的位置,是在函数getResult之后的,如果在它之前的话,会提示函数不存在。js加载顺序是从上开始,在之前调用没创建的,不能成功。注意这里是指引入的js文件,如果是同一个js文件或者当前页面的js中,先执行调用,然后再写函数也是没有问题的,但是如果先执行调用引入js文件中的函数,然后再引入js文件,就会提示函数不存在。</p> <pre class="brush:php;toolbar:false"><script></script> <script> function jsonp_fun(){ $.ajax({ url:&#39;http://localhost:8888/other/index.jsp&#39;, type:&#39;post&#39;, dataType:&#39;text&#39;, success:function(data){ console.log(data); } }); } function getResult(data){ alert(data.result); } </script> <script></script></pre> <p style="text-align: left;">然后other.js</p> <p style="text-align: left;">getResult({"result":"this is other domain's data"});</p> <p style="text-align: left;">也就是在jsonp/index.jsp页面写好函数,然后引入其他域的js传入参数去调用这个函数,这里的参数你可以先看做是其他域服务器的接口返回的数据。</p> <p style="text-align: left;">刷新页面,效果当然是</p> <p style="text-align: left;">弹出alert框,this is other domain's data</p> <p style="text-align: left;"><strong>3.2 模拟接口访问</strong></p> <p style="text-align: left;">看到这里,你会不会还是想不懂,上面js弄啥的,传个死的数据,有什么实际意义吗?,其实script的src不仅可以接js的地址,还可以接servlet的地址,也就是http接口地址,所以接下来,懒得写servlet,这里还是写jsp当做接口,在other项目中新建other.jsp页面,内容如下:</p> <pre class="brush:php;toolbar:false"> </pre> <p style="text-align: left;">内容很简单,也就是接受一个params的参数,然后返回数据给调用者。</p> <p style="text-align: left;">我们在jsonp/index.jsp中加上</p> <pre class="brush:php;toolbar:false"><script></script></pre> <p style="text-align: left;">看到这个地址,你是不是很熟悉,不熟悉的证明你用servlet用蠢了,jsp也是servlet,流程就是页面一加载的时候,script标签就会去发送请求,然后返回数据。那么我们刷新页面,看看效果。</p> <p style="text-align: left;"><img title="" alt="Jsonp solves the cross-domain problem of ajax" src="https://img.php.cn/upload/article/000/061/021/0e81fae80d6de5943ac04118ef82b69e-3.png"></p> <p style="text-align: left;">Uncaught SyntaxError: Unexpected identifier</p> <p style="text-align: left;">报错了,如上,然后代码有问题?No,点击错误,你会看到请求的东西也打印出来了,就是提示错误,表示这个东西浏览器不认识,其实是script不认识啦。</p> <p style="text-align: left;"><img title="" alt="Jsonp solves the cross-domain problem of ajax" src="https://img.php.cn/upload/article/000/061/021/0e81fae80d6de5943ac04118ef82b69e-4.png"></p> <p style="text-align: left;">还不明白,那么你去页面加上如下内容,你看报不报错!!肯定报错</p> <pre class="brush:php;toolbar:false"><script> ajax cross success,the server receive params : jsonp_param </script></pre> <p style="text-align: left;">那么js不能解析,我们换一种思路,要是我们输出的是JSON字符串或者调用当前页面函数的字符串了,类似于3.1中返回的getResult({“result”:”this is other domain's data”});</p> <p style="text-align: left;">所以改造一下,把other.jsp中的内容改成</p> <pre class="brush:php;toolbar:false"> </pre> <p style="text-align: left;">别忘了,之前jsonp/index.jsp中我们定义了,那么加入引用之后,依然记得getResult函数与引入函数的先后顺序问题。</p> <pre class="brush:php;toolbar:false"><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中文网其它相关文章!
推荐阅读:
The above is the detailed content of Jsonp solves the cross-domain problem of ajax. For more information, please follow other related articles on the PHP Chinese website!