IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    逐渐深入地理解Ajax

    dwqs发表于 2015-06-03 00:17:42
    love 0

    Ajax的基本原理是:XMLHttpRequest对象(简称XHR对象),XHR为向服务器发送请求和解析服务器响应提供了流畅的接口。能够以异步方式从服务器获得更多信息。意味着用户不必刷新页面也能取得新数据,然后通过DOM将数据插入到页面中。

    XMLHttpRequest对象方法

    about(): 停止当前的请求;
    open("method","URL",[asyncFlag]) :启动请求

    XHR的基本用法

    在使用XHR对象时,要调用的第一个方法是open()方法,它有三个参数,第一个参数是:需要发送请求的类型(get或者post),第二个参数是请求的url,第三个参数是请求的布尔值(true是异步,false是同步);

    1. xhr.open('get','http://127.0.0.1/ajax/ajax.php',false)
    2. <div class="md-section-divider">div>

    如上代码会启动一个get请求ajax.php,但是请注意:open方法并不会真正发请求,而只是启动一个请求以备发送;要发送真正请求必须使用send()方法;如下:

    1. xhr.open('get','http://127.0.0.1/ajax/ajax.php',false);
    2. xhr.send(null);
    3. <div class="md-section-divider">div>

    send 的方法接收一个参数,需要请求发送的数据,如果请求不需要发送数据,需要传送一个null,因为对于有些浏览器这是必须的;上面第三个参数传的是false,是同步请求,服务器接收到响应后再继续执行后面的代码,响应后的数据会自动填充XHR对象的属性,XHR有以下属性:
    responseText: 作为响应主体被返回的文本。

    responseXML: 如果响应的内容是”text/xml” 或application/xml,这个属性将保存包含响应数据的XML DOM文档;
    status: 响应http状态;
    statusText: http状态说明;
    在接收到响应后,第一步是检查status状态,如果状态时200,说明已经成功返回,此时responseText属性已经就绪;如果状态是304,说明资源未被修改,可以直接使用浏览器缓存的版本,当然,响应是有效的;如下ajax请求代码:

    1. // 创建xhr对象方法如下:
    2. function createXHR(){
    3. var xhr;
    4. if (window.XMLHttpRequest){
    5. // code for IE7+, Firefox, Chrome, Opera, Safari
    6. xhr=new XMLHttpRequest();
    7. }else{ // code for IE6, IE5
    8. xhr=new ActiveXObject("Microsoft.XMLHTTP");
    9. }
    10. return xhr;
    11. }
    12. var xhr = createXHR();
    13. xhr.open('get','http://127.0.0.1/ajax/ajax.php',false);
    14. xhr.send(null);
    15. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    16. console.log(xhr.responseText);
    17. }else {
    18. console.log(xhr.status);
    19. }

    ajax.php代码如下:

    1. php
    2. $data = json_decode(file_get_contents("php://input"));
    3. echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
    4. ?>

    发ajax请求后,在控制台中打印如下:
    sds
    说明已经请求成功;

    上面的demo代码是同步请求,但是有时候我们需要发送异步请求,才能让javascript后续代码继续执行而不会堵塞,此时,我们可以检测XHR对象的readyState属性,该属性表示请求/响应当前活动阶段;这个属性取值如下:

    • 0:未初始化。尚未调用open()方法;
    • 1:启动。已经调用open()方法,但未调用send()方法;
    • 2:发送。已经调用send()方法,但尚未接收到响应;
    • 3:接收。已经接收到部分数据;
    • 4:完成。已经接收到全部响应数据,而且可以在客户端使用了;

    readyState 属性值由一个值变为另一个值,就会触发一次readystatechange事件。可以利用这个事件检测每次状态变化后的readyState值,但是必须在调用open()方法之前指定onreadystatechange事件;如下代码:

    1. // 创建xhr对象方法如下:
    2. function createXHR(){
    3. var xhr;
    4. if (window.XMLHttpRequest){
    5. // code for IE7+, Firefox, Chrome, Opera, Safari
    6. xhr=new XMLHttpRequest();
    7. }else{
    8. // code for IE6, IE5
    9. xhr=new ActiveXObject("Microsoft.XMLHTTP");
    10. }
    11. return xhr;
    12. }
    13. var xhr = createXHR();
    14. xhr.onreadystatechange = function(){
    15. if(xhr.readyState == 4) {
    16. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    17. console.log(xhr.responseText);
    18. }else {
    19. console.log(xhr.status);
    20. }
    21. }
    22. }
    23. xhr.open('get','http://127.0.0.1/ajax/ajax.php',false);
    24. xhr.send(null);

    如上代码,在处理onreadystatechange事件时使用了xhr对象,没有使用this对象,原因是onreadystatechange事件处理程序的作用域的问题;如果使用this对象,在有的浏览器下会执行失败,或者导致错误发生;

    理解Http头部信息

    每个http请求和响应都会带有响应的头部信息,xhr对象也提供了操作这两种头部(请求头部和响应头部的)信息的方法;

    默认情况下,在发送XHR请求的同时,还会发送下列头部信息:

    • Accept: 浏览器能够处理的内容类型;
    • Accept-Charset: 浏览器能够显示的字符集;
    • Accept-Encoding: 浏览器能够处理的压缩编码;
    • Accept-Language: 浏览器当前设置的语言;
    • Connection: 浏览器与服务器之间连接的类型;
    • Cookie:当前页面设置的cookie;
    • Host:发出请求页面所在的域;
    • Referer:发出请求的页面url。
    • User-Agent: 浏览器的用户代理字符串。

    如下ajax.php请求所示:
    sd
    我们还可以使用setRequestHeader()方法可以设置自定义的请求头部信息,这个方法接收2个参数:头部字段的名称和头部字段的值;要成功发送请求头部信息,必须在调用open()方法之后且调用send()方法之前调用setRequestHeader();如下demo所示:

    1. xhr.open('get','http://127.0.0.1/ajax/ajax.php',false);
    2. xhr.setRequestHeader("myHeader","myValue");
    3. xhr.send(null);

    截图如下:
    sdssdas
    调用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串,如上代码中在onreadystatechange事件中添加getAllResponseHeaders()方法:

    1. xhr.onreadystatechange = function(){
    2. if(xhr.readyState == 4) {
    3. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    4. var myHeader = xhr.getAllResponseHeaders();;
    5. console.log(myHeader);
    6. }else {
    7. console.log(xhr.status);
    8. }
    9. }

    打印如下:
    sdsda

    理解GET请求

    在ajax中,有常见的get请求或者post请求,使用get请求时,我们是把参数的名-值对经过encodeURIComponent()进行编码,然后放到URL的末尾,所有名值对必须由和好(&)分割;如下代码:

    1. xhr.open('get','http://127.0.0.1/ajax/ajax.php?name1=value1&name2;=value2',true);

    下面我们可以封装一个方法可以辅助向现有的URL的末尾添加查询字符串参数;

    1. function addURLParam(url,name,value) {
    2. url += url.indexOf("?") == -1 ? "?" : "&";
    3. url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    4. return url;
    5. }

    如下代码测试:

    1. // 创建xhr对象方法如下:
    2. function createXHR(){
    3. var xhr;
    4. if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safari
    5. xhr=new XMLHttpRequest();
    6. }else{ // code for IE6, IE5
    7. xhr=new ActiveXObject("Microsoft.XMLHTTP");
    8. }
    9. return xhr;
    10. }
    11. var xhr = createXHR();
    12. xhr.onreadystatechange = function(){
    13. if(xhr.readyState == 4) {
    14. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    15. var myHeader = xhr.getAllResponseHeaders();;
    16. console.log(myHeader);
    17. console.log(xhr.responseText);
    18. }else {
    19. console.log(xhr.status);
    20. }
    21. }
    22. }
    23. var url = "http://127.0.0.1/ajax/ajax.php";
    24. url = addURLParam(url,"name1","value1");
    25. url = addURLParam(url,"name2","value2");
    26. xhr.open('get',url,true);
    27. xhr.setRequestHeader("myHeader","myValue");
    28. xhr.send(null);
    29. function addURLParam(url,name,value) {
    30. url += url.indexOf("?") == -1 ? "?" : "&";
    31. url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
    32. return url;
    33. }

    如下截图所示:
    sdasfdfsd

    理解POST请求

    Post 请求时作为请求的主体提交,post请求的主体可以是非常多的数据,而且格式不限;在open方法的第一个参数传入post,就可以初始化post请求,如下:

    1. xhr.open('post',"http://127.0.0.1/ajax/ajax.php",true)

    接下来我们需要使用send()方法来发送数据,传入的参数可以是任何的字符串或者form表单序列化之后的数据;比如我们现在可以使用xhr来模仿表单提交数据,首先我们需要将Content-Type头部信息设置为application/x-www-form-urlencoded, 也就是表单提交的内容类型,其次以适当的格式创建一个字符串,比如form表单序列化数据,然后通过xhr发送到服务器端,

    如下HTML代码:

    1. id="form">
    2. name="user-name" value="aaa"/>
    3. name="user-email" value="233"/>

    JS代码如下:

    1. // 序列化的代码
    2. function serialize(form) {
    3. var arrs = [],
    4. field = null,
    5. i,
    6. len,
    7. j,
    8. optLen,
    9. option,
    10. optValue;
    11. for(i = 0,len = form.elements.length; i < len; i++) {
    12. field = form.elements[i];
    13. switch(field.type) {
    14. case "select-one":
    15. case "select-multiple":
    16. if(field.name.length) {
    17. for(j = 0,optLen = field.options.length; j < optLen; j++) {
    18. option = field.options[j];
    19. if(option.selected) {
    20. optValue = '';
    21. if(option.hasAttribute) {
    22. optValue = option.hasAttribute("value") ? option.value : option.text;
    23. }else {
    24. optValue = option.attributes["value"].specified ? option.value : option.text;
    25. }
    26. arrs.push(encodeURIComponent(field.name) + "=" +encodeURIComponent(optValue));
    27. }
    28. }
    29. }
    30. break;
    31. case undefined: //字段集
    32. case "file": // 文件输入
    33. case "submit": // 提交按钮
    34. case "reset": // 重置按钮
    35. case "button": // 自定义按钮
    36. break;
    37. case "radio": // 单选框
    38. case "checkbox": // 复选框
    39. if(!field.checked) {
    40. break;
    41. }
    42. /* 执行默认动作 */
    43. default:
    44. // 不包含没有名字的表单字段
    45. if(field.name.length) {
    46. arrs.push(encodeURIComponent(field.name) + "=" +encodeURIComponent(field.value));
    47. }
    48. }
    49. }
    50. return arrs.join("&");
    51. }
    52. var url = "http://127.0.0.1/ajax/ajax.php";
    53. xhr.open('post',"http://127.0.0.1/ajax/ajax.php",true);
    54. xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    55. var form = document.getElementById("form");
    56. xhr.send(serialize(form));

    之后我们可以看到form表单序列化之后传过去的数据如下:
    sdasd

    XMLHttpRequest 2级

    XMLHttpRequest 1级只是把已有的xhr对象的实现细节描述出来了,而XMLHttpRequest 2级是在原来的基础上增加了一些规范,但所有的浏览器只是实现了他规定的部分内容;如下几个:

    理解FormData

    现在web应用中频繁使用的一项功能是form表单序列化,XMLHttpRequest 2级定义了FormData类型,使用FormData获取数据与表单序列化数据一样,但是更简洁方便;

    支持FormData浏览器有:firefox4+, safari5+, chrome和Android3+版的webkit.

    比如我现在提交form表单数据如下demo:

    HTML代码:

    1. id="form">
    2. name="user-name" value="aaa"/>
    3. name="user-email" value="233"/>
    4. class="md-section-divider">

    JS代码如下:

    1. var url = "http://127.0.0.1/ajax/ajax.php";
    2. xhr.open('post',"http://127.0.0.1/ajax/ajax.php",true);
    3. var form = document.getElementById("form");
    4. xhr.send(new FormData(form));
    5. <div class="md-section-divider">div>

    在chrome浏览器下如下:
    sdasd
    在firefox浏览器如下:
    ff
    dfsdf
    使用formData的方便之处体现在不必明确地在XHR对象上设置请求头部,XHR对象能识别传入的数据类型是FormData实例,并配置适当的头部信息。

    理解超时设定

    IE8为XHR对象添加了一个timeout属性,表示请求在等待响应多少毫秒之后停止,在给timeout设置一个数值后,如果在规定的时间之内浏览器没有接受到响应,那么就会触发ontimeout事件,那么就会终止ajax请求,如下代码:

    1. var url = "http://127.0.0.1/ajax/ajax.php";
    2. xhr.open('get',"http://127.0.0.1/ajax/ajax.php",true);
    3. xhr.timeout = 1;
    4. xhr.ontimeout = function(){
    5. alert("111");
    6. };
    7. xhr.send(null);
    8. <div class="md-section-divider">div>

    如上我把代码timeout设置1毫秒,如果请求1毫秒之后没有返回数据的话,就执行ontimeout事件,并且请求停止掉,目前我测试的浏览器chrome和firefox都支持;如下chrome浏览器截图如下:
    ![sdasda](http://images0.cnblogs.com/blog2015/561794/201505/232058067191212.png)

    进度事件

    Progress Events规范是W3C的一个工作草案,定义了与客服端服务器通信有关的事件,这些事件最早是针对XHR操作的,有以下6个事件;

    • loadstart: 在接收到响应数据的第一个字节时触发;
    • progress: 在接收响应期间持续不断的触发;
    • error: 在请求发生错误时触发;
    • abort: 在因为调用abort()方法而终止连接时触发;
    • load:在接收到完整的响应数据时触发;
    • loadend:在通信完成或者触发error,abort或load事件后触发;(这个事件基本上不使用的。)

    支持前5个事件的浏览器有:firefox3.5+,safari4+,chrome,IOS版的safari和android版的webkit,opera(从11开始),IE8+只支持load事件;

    load事件

    Firefox在实现XHR对象的某个版本时,为了简化异步交互模型,实现了load事件,用以替代readystatechange事件,响应接收完毕后触发load事件,因此就没有必要检查readyState属性了;
    目前支持的浏览器有:firefox,opera,chrome和safari
    如下代码演示:

    1. var xhr = createXHR();
    2. xhr.onload = function(){
    3. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    4. console.log(xhr.responseText);
    5. }else {
    6. console.log(xhr.status);
    7. }
    8. }
    9. xhr.open('get',"http://127.0.0.1/ajax/ajax.php",true);
    10. xhr.send(null);
    11. <div class="md-section-divider">div>

    progress事件

    这个事件在浏览器接收数据期间周期性的触发,而onprogress事件处理程序会接收一个event对象,包含三个属性,lengthComputable是一个表示进度信息是否可用的布尔值;position表示已经接收的字节数,totalSize表示根据Content-Length响应头部确定的预期总字节数。如下代码:

    1. var xhr = createXHR();
    2. xhr.onload = function(){
    3. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    4. console.log(xhr.responseText);
    5. }else {
    6. console.log(xhr.status);
    7. }
    8. }
    9. xhr.onprogress = function(event) {
    10. var divStatus = document.getElementById("status");
    11. if (event.lengthComputable){
    12. divStatus.innerHTML = "Received " + event.position + " of " +
    13. event.totalSize +" bytes";
    14. }
    15. };
    16. xhr.open('get',"http://127.0.0.1/ajax/ajax.php",true);
    17. xhr.send(null);
    18. <div class="md-section-divider">div>

    截图运行如下:
    sdas

    跨源资源共享

    通过XHR实现ajax通信的一个主要限制,来源于跨域安全策略。默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源,因为浏览器这样做的限制就是防止一些恶意操作;那么CORS(跨源资源共享)的基本原理是:需要由服务器发送一个响应标头就可以让浏览器与服务器进行沟通;
    比如我现在做一个demo来试着看,假如我现在在hosts文件下绑定2个IP地址:如下:
    127.0.0.1 abc.example1.com
    127.0.0.1 def.example2.com
    那么现在我 abc.example1.com下有一个页面ajax.html,如下代码:

    1. var xhr = createXHR();
    2. xhr.onload = function(){
    3. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    4. console.log(xhr.responseText);
    5. }else {
    6. console.log(xhr.status);
    7. }
    8. }
    9. xhr.open('POST',"http://def.example2.com/ajax/ajax.php",true);
    10. xhr.send(null);
    11. <div class="md-section-divider">div>

    如上代码,在给域下def.example2.com 下的ajax.php发ajax请求,因为是同源策略问题,肯定不成功,如下所示:
    error
    现在我们在def.example2.com域下php设置头部即可;如下代码:

    1. header("Access-Control-Allow-Origin: *");
    2. <div class="md-section-divider">div>

    ajax.php代码如下:

    1. php
    2. header("Access-Control-Allow-Origin: *");
    3. $data = json_decode(file_get_contents("php://input"));
    4. echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
    5. ?>
    6. class="md-section-divider">

    这样就可以认为大功告成,很高兴,看到书上或者网上查找资料后,也是这么说的,但是呢 当我再次请求这个页面的时候http://abc.example1.com/ajax/ajax.html 还是发现因为同源策略的问题,请求不成功,查看控制台这样的错误,如下:

    1. XMLHttpRequest cannot load http://def.example2.com/ajax/ajax.php. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://abc.example1.com' is therefore not allowed access.
    2. <div class="md-section-divider">div>

    也是同源策略的问题,不允许访问;继续通过网上查找资料,发现原来是我的php.ini里面的配置出了问题,在php安装目录下找到php.ini文件output_buffering默认为off的。我现在把它设为on就OK了。如下截图所示:
    ![ssds](http://images0.cnblogs.com/blog2015/561794/201505/232101296414905.png)
    在php文件头部设置 header,

    1. header("Access-Control-Allow-Origin:*");
    2. <div class="md-section-divider">div>

    星号意思是所有的请求都可以,但是设置并不安全,所以我们可以针对当前的这个页面域下设置,如下:

    1. php
    2. header("Access-Control-Allow-Origin: http://abc.example1.com");
    3. $data = json_decode(file_get_contents("php://input"));
    4. echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
    5. ?>
    6. class="md-section-divider">

    我们继续截图如下看看:
    sdas
    同样也可以访问;但是上面的在IE7-8下还是会报错,因为同源策略的问题,会报错,如下截图所示:
    dgfsdf
    标准浏览器下比如chrome或者firefox不会报错,那么我们可以看下在IE下,IE如何实现对CORS的支持;
    IE对CORS的实现方式如下:
    微软在IE中引入XDR(XDomainRequest)类型,这个对象与XHR类似,但是能实现安全可靠的跨域通信,XDR对象部分实现了W3C的CORS规范;XDR与XHR不同之处如下:

    1. Cookie不会随请求发送,也不会随响应返回。
    2. 只能设置请求头部信息中的Content-Type字段。
    3. 不能访问响应头部信息。
    4. 只支持get和post请求。

    这些变化使CSRF(Cross-Site Request Forgery,跨站点请求伪造)和XSS(Cross-Site Scripting,跨站点脚本)的问题得到了缓解,被请求的资源可以根据它认为合适的任意数据(用户代理,来源页面等)来决定是否设置Accept-Control-Allow-Origin头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程资源明确地识别XDR请求。
    XDR 对象的使用方法与XHR对象非常相似,先创建一个XDomainRequest对象,如下:

    1. var xdr = new XDomainRequest();

    再调用open()方法,再调用send()方法;但是XDR对象的open()方法只接受2个参数,请求的类型和URL;

    所有XDR的请求都是异步的,不能用来创建同步请求,请求成功后,会触发load事件,响应的数据保存在responseText属性中;如下demo,我们继续看下在IE7-8下如何可以跨域请求成功;如下代码:

    1. var xdr = new XDomainRequest();
    2. xdr.onload = function() {
    3. alert(xdr.responseText);
    4. };
    5. xdr.open('POST',"http://def.example2.com/ajax/ajax.php",true);
    6. xdr.send(null);

    现在我们刷新下页面可以看到请求成功了,如下所示:
    sdas
    65464
    如果响应失败的话,会调用error方法,通知开发人员,如下代码:

    1. var xdr = new XDomainRequest();
    2. xdr.onload = function() {
    3. alert(xdr.responseText);
    4. };
    5. xdr.onerror = function(){
    6. alert("响应失败");
    7. };
    8. xdr.open('POST',"http://def.example2.com/ajax/ajax.php",true);
    9. xdr.send(null);

    与XHR一样,XDR对象也支持timeout属性以及ontimeout事件处理程序,如下代码:

    1. xdr.timeout = 1;
    2. xdr.ontimeout = function(){
    3. alert("Request took too long.");
    4. };

    请求超过1毫秒后没有响应,就调用ontimeout事件;

    标准浏览器下实现对CORS的实现

    其实实现方式在第一次讲解跨域的时候我们已经讲过了,可以翻到上面,但是我们现在重新来理一遍;

    Firefox3.5+,Safari4+,chrome,ios版的safari和android平台中的webkit都通过XMLHttpRequest对象实现了CORS的原生支持;如下代码:

    1. var xhr = new XMLHttpRequest();
    2. xhr.onreadystatechange = function(){
    3. if (xhr.readyState == 4){
    4. if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    5. alert(xhr.responseText);
    6. }else {
    7. console.log(xhr.status);
    8. }
    9. }
    10. }
    11. xhr.open('POST',"http://def.example2.com/ajax/ajax.php",true);
    12. xhr.send(null);

    如上代码即可就可以实现在标准浏览器下ajax的跨域通信问题;

    与IE中的XDR对象不同,通过跨域XHR对象可以访问status和statusText属性,而且还支持同步请求,跨域XHR对象也有一些限制,如下限制:

    1. 不能使用setRequestHeader()设置自定义头部;
    2. 不能发送和接收cookie。
    3. 调用getAllResponseHeaders()方法总会返回空字符串。

    跨浏览器的CORS的实现

    如上介绍的是对IE下和标准浏览器下2种方案实现跨域的实现方案,下面我们可以来封装下对常用的所有浏览器支持下,首先我们先检查是否存在withCredentials 属性(标准浏览器下有这个属性),再结合检测XDomainRequest对象是否存在(就可以检测到IE),如下是所有封装的代码:

    1. function createCORSRequest(method,url) {
    2. var xhr = new XMLHttpRequest();
    3. if("withCredentials" in xhr) {
    4. xhr.open(method,url,true);
    5. }else if(typeof XDomainRequest != 'undefined') {
    6. xhr = new XDomainRequest();
    7. xhr.open(method,url);
    8. }else {
    9. xhr = null;
    10. }
    11. return xhr;
    12. }
    13. var request = createCORSRequest('POST',"http://def.example2.com/ajax/ajax.php");
    14. if(request) {
    15. request.onload = function(){
    16. alert(request.responseText);
    17. }
    18. request.send();
    19. }

    浏览器支持程度:IE7+,firefox3.5+,safari4+,chrome3+等;

    JSONP跨域技术的基本原理

    Jsonp 跨域get请求是如何实现的;我们先来了解下为什么会出现跨域?

    Javascript是一种在web开发中经常使用的前端动态脚本技术,在javascript中,有一个很重要的安全限制,被称为same-Origin-Policy同源策略,这一策略对于javascript代码能够访问的页面内容作了很重要的限制,即javascript只能访问与包含它的文档在同一域下的内容;

    JSONP 的基本原理是:利用在页面中创建



沪ICP备19023445号-2号
友情链接