如何处理在Ajax数据传输中的跨域问题

Ajax

Ajax技术,即在不需要刷新页面的情况下从服务器获取数据进行数据交互,而实现Ajax技术的核心就是使用XHR对象(XMLHttpRequet对象),虽然对象中包含XML,但是在通过Ajax进行数据交互的时候并不一定要使用XML格式。
在使用XHR对象创建一个完整的Ajax请求要使用到open(),send()和readyStatechange事件

open()

open()方法,用于启动一个请求以备发送,接收三个参数,依次为发送请求的类型(GET,POST),请求的URL地址,布尔值(是否为异步执行).

send()

send()方法,用于执行一个请求并将该请求发送至服务器实现数据通信,接收一个参数,即要发送给服务器的数据,通常为JSON类型的字符串,如果没有,可以为空或者null,只有当调用了send()方法之后,请求才会发送给服务器端。

readyStatechange事件

在数据传输的过程中,我们可以通过status或者readyState属性来判断HTTP响应的状态,当status的状态码等于200时,代表数据已经成功传输,浏览器已经接收到了服务器传输的数据,此外当status的状态码等于304时,表示请求的资源没有被修改,可以直接调用缓存中的数据,也意味着成功响应。同时还可以通过readyState属性来检测响应的状态,当readyState等于0时,表示未初始化,open()方法未执行,1表示启动,执行open()方法,未执行send()方法,2表示发送,成功执行send()方法,3表示接收,已经接收到一部分的相应数据,4表示完成,接收全部的相应数据,通常在判断时,当readyState等于4时代表响应完全,而readyStatechange事件就是当上述两个属性的状态改变时调用,可以通过该事件来获取响应的数据资源,以下为实例

        let xhr = new XMLHttpRequest();
        xhr.open("post","http:192.168.43.237:8080/sign",true);
        xhr.onreadyStatechange = function(){
            if(xhr.readyState == 4){
                 if(xhr.status>=200 && xhr.status<300 || xhr.status == 304){
                         console.log(xhr.responseText);
                     }
                }
        }
        xhr.send(null);

(注意:open()方法中的URL路径,必须和当前页面所处同一个域,同一个端口和协议,否则就会出现跨域问题导致传输被拒绝)

为什么会出现跨域问题

我们在使用Ajax来与服务器沟通本质上是通过XHR(XMLHttpRequest)对象来实现的,在默认情况下,XHR对象只能访问与包含它的页面在同一个域中的资源,换言之,XHR对象只能访问与包含页面在同一个域名,同一个协议,同一个端口中的资源,而这三者中有一种不同,便会判断为不同域,即产生跨域问题,导致数据不能进行正常的传输。

192.168.43.237:3000/sign | 192.168.43.237:3000/use 同一个域中
192.168.43.237:3000/sign | 192.168.43.237:8000/use 不同域中
192.168.43.130:3000/sign | 192.168.43.237:3000/use 不同域中

如何解决跨域问题

CORS

CORS(Cross-Origin Resource Sharing 跨域资源共享),是W3C的一个工作草案,定义了在必须访问跨域资源时,浏览器如何与服务器进行沟通。实现CORS的核心思想是通过改变HTTP协议的请求头内容让浏览器与服务器进行沟通,从而决定响应或请求是否成功或失败。
在通过GET或POST向服务器发送请求时,浏览器会附加一个Origin头部,它包含了该请求页面的源信息(域名,端口号和协议)

Origin:“http://192.168.43.237:3000”

如果服务器端同意该请求,就会通过Access-Control-Allow-Origin头部返回相同的源信息(如果是公共资源,则会返回“*”),如果没有这个头部,或者头部的源信息不匹配,浏览器就会拒绝该请求。

Access-Control-Allow-Origin:“http://192.168.43.237:3000”或
Access-Control-Allow-Origin:“*”

根据以上规定,我们就可以通过在服务器端通过自定义修改Access-Control-Allow-Origin头部来实现跨域访问

允许其他的域进行访问
Access-Control-Allow-Origin:“*”

允许通过get,post请求访问
Access-Control-Allow-Methods:get,post

设置响应头
Access-Control-Allow-Headers:Content-type
图像Ping

图像Ping是与服务器进行简单,单项的跨域通信的一种方式,因为在网页中,可以通过标签的路径来获取任意地方的图像信息,不存在跨域的问题,通过该方法,请求的数据是通过查询字符串形式发送的,而响应可以是任意内容。

        function Ping(){
             let img = new Image();
                
             var handler = function(event){
                 switch(event.type){
                    case "load":
                        console.log("Done");
                        break;
                    case "error":
                        console.log("Done");
                        break;
                    default:
                        console.log("error");
                 }
              }
              img.onload = handler;
              img.onerror = handler;    
              img.src = "http:192.168.43.237:3000/ping?name=xiaohong";
       }

该函数通过事件委托模式为img添加了load和error事件,由于图片的传输不受域的限制,所以服务器端可以通过get方法接收到img的地址以及地址中包含的参数name,同时通过load和error事件可以实时了解到用户点击事件和图片加载的次数
但是通过图像Ping实现跨域有两个主要的缺点,一是只能发送GET请求,而是无法访问服务器的响应文本,即单方向的跨域通信,所以对于该方法而言,最主要的用途是用于跟踪用户的点击次数和广告的曝光次数等。

JSONP

JSONP是JSON with padding(参数式JSON)的简写,与图像Ping实现跨域的原理有相似,JSONP是通过动态创建script元素,通过script元素的src来实现服务器和浏览器之间的跨域访问,通过参数式JSON,将回掉函数变为URL路径的参数,因为JSONP是有效的javascript代码,所以在服务器访问到该路径是,就会执行回掉函数来处理需要发送的响应数据。
下面就是一个典型的JSONP请求
script.src = "http://192.168.43.237:3000/ping?callback=handler";
以下为一个简单的JSONP请求实例

 let btn = document.getElementById("button");   
 btn.onclick = function(){
      let script = document.createElement("script");
      script.src = "http://192.168.43.237:3000/ping?callback=handler";
      document.body.insertBefore(script, document.body.firstChild);  
 }
 
 function handler(response){
      console.log(responseText);
 } 

与图像Ping方法相比,JSONP的优势在于可以获取到相应数据文本以及支持在浏览器和服务器之间实现双向通信,不过对于JSONP方法而言,不足之处在于只能通过GET请求类型,其次由于JSONP是在其他域中请求数据,所以如果在相应中包含恶意代码的话,会对Web访问当中的安全因素造成影响。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容