xmlhttprequest 需要跨域资源共享怎么解决

xmlhttprequest 需要跨域资源共享怎么解决,第1张

XMLHttpRequest是一个浏览器接口,使得Javascript可以进行HTTP(S)通信。 最早,微软在IE 5引进了这个接口。因为它太有用,其他浏览器也模仿部署了,ajax *** 作因此得以诞生。 但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同。HTML 5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。 这个XMLHttpRequest的新版本,提出了很多有用的新功能,将大大推动互联网革新。本文就对这个新版本进行详细介绍。 一、老版本的XMLHttpRequest对象 在介绍新版本之前,我们先回顾一下老版本的用法。 首先,新建一个XMLHttpRequest的实例。 var xhr = new XMLHttpRequest() 然后,向远程主机发出一个HTTP请求。 复制代码 代码如下: xhr.open('GET', 'example.php') xhr.send() 接着,就等待远程主机做出回应。这时需要监控XMLHttpRequest对象的状态变化,指定回调函数。 xhr.onreadystatechange = function(){ if ( xhr.readyState == 4 &&xhr.status == 200 ) { alert( xhr.responseText ) } else { alert( xhr.statusText ) } } 上面的代码包含了老版本XMLHttpRequest对象的主要属性: 复制代码 代码如下: * xhr.readyState:XMLHttpRequest对象的状态,等于4表示数据已经接收完毕。 * xhr.status:服务器返回的状态码,等于200表示一切正常。 * xhr.responseText:服务器返回的文本数据 * xhr.responseXML:服务器返回的XML格式的数据 * xhr.statusText:服务器返回的状态文本。 二、老版本的缺点 老版本的XMLHttpRequest对象有以下几个缺点: * 只支持文本数据的传送,无法用来读取和上传二进制文件。 * 传送和接收数据时,没有进度信息,只能提示有没有完成。 * 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。 三、新版本的功能 新版本的XMLHttpRequest对象,针对老版本的缺点,做出了大幅改进。 复制代码 代码如下: * 可以设置HTTP请求的时限。 * 可以使用FormData对象管理表单数据。 * 可以上传文件。 * 可以请求不同域名下的数据(跨域请求)。 * 可以获取服务器端的二进制数据。 * 可以获得数据传输的进度信息。 下面,我就一一介绍这些新功能。 四、HTTP请求的时限 有时,ajax *** 作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。 新版本的XMLHttpRequest对象,增加了timeout属性,可以设置HTTP请求的时限。 xhr.timeout = 3000 上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout事件,用来指定回调函数。 复制代码 代码如下: xhr.ontimeout = function(event){ alert('请求超时!') } 目前,Opera、Firefox和IE 10支持该属性,IE 8和IE 9的这个属性属于XDomainRequest对象,而Chrome和Safari还不支持。 五、FormData对象 ajax *** 作往往用来传递表单数据。为了方便表单处理,HTML 5新增了一个FormData对象,可以模拟表单。 首先,新建一个FormData对象。 var formData = new FormData() 然后,为它添加表单项。 formData.append('username', '张三') formData.append('id', 123456) 最后,直接传送这个FormData对象。这与提交网页表单的效果,完全一样。 xhr.send(formData) FormData对象也可以用来获取网页表单的值。 复制代码 代码如下: var form = document.getElementById('myform') var formData = new FormData(form) formData.append('secret', '123456')// 添加一个表单项 xhr.open('POST', form.action) xhr.send(formData) 六、上传文件 新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件。 假定files是一个"选择文件"的表单元素(input[type="file"]),我们将它装入FormData对象。 复制代码 代码如下: var formData = new FormData() for (var i = 0i <files.lengthi++) { formData.append('files[]', files[i]) } 然后,发送这个FormData对象。 xhr.send(formData) 七、跨域资源共享(CORS) 新版本的XMLHttpRequest对象,可以向不同域名的服务器发出HTTP请求。这叫做"跨域资源共享"(Cross-origin resource sharing,简称CORS)。 使用"跨域资源共享"的前提,是浏览器必须支持这个功能,而且服务器端必须同意这种"跨域"。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样。 xhr.open('GET', 'other.server/and/path/to/script') 目前,除了IE 8和IE 9,主流浏览器都支持CORS,IE 10也将支持这个功能。服务器端的设置,请参考《Server-Side Access Control》。 八、接收二进制数据(方法A:改写MIMEType) 老版本的XMLHttpRequest对象,只能从服务器取回文本数据(否则它的名字就不用XML起首了),新版则可以取回二进制数据。 这里又分成两种做法。较老的做法是改写数据的MIMEType,将服务器返回的二进制数据伪装成文本数据,并且告诉浏览器这是用户自定义的字符集。 xhr.overrideMimeType("text/plaincharset=x-user-defined") 然后,用responseText属性接收服务器返回的二进制数据。 var binStr = xhr.responseText 由于这时,浏览器把它当做文本数据,所以还必须再一个个字节地还原成二进制数据。 复制代码 代码如下: for (var i = 0, len = binStr.lengthi <len++i) { var c = binStr.charCodeAt(i) var byte = c &0xff } 最后一行的位运算"c &0xff",表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。 八、接收二进制数据(方法B:responseType属性) 从服务器取回二进制数据,较新的方法是使用新增的responseType属性。如果服务器返回文本数据,这个属性的值是"TEXT",这是默认值。较新的浏览器还支持其他值,也就是说,可以接收其他格式的数据。 你可以把responseType设为blob,表示服务器传回的是二进制对象。 复制代码 代码如下: var xhr = new XMLHttpRequest() xhr.open('GET', '/path/to/image.png') xhr.responseType = 'blob' 接收数据的时候,用浏览器自带的Blob对象即可。 var blob = new Blob([xhr.response], {type: 'image/png'}) 注意,是读取xhr.response,而不是xhr.responseText。 你还可以将responseType设为arraybuffer,把二进制数据装在一个数组里。 复制代码 代码如下: var xhr = new XMLHttpRequest() xhr.open('GET', '/path/to/image.png') xhr.responseType = "arraybuffer" 接收数据的时候,需要遍历这个数组。 复制代码 代码如下: var arrayBuffer = xhr.response if (arrayBuffer) { var byteArray = new Uint8Array(arrayBuffer) for (var i = 0i <byteArray.byteLengthi++) { // do something } } 更详细的讨论,请看Sending and Receiving Binary Data。 九、进度信息 新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。 它分成上传和下载两种情况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。 我们先定义progress事件的回调函数。 复制代码 代码如下: xhr.onprogress = updateProgress xhr.upload.onprogress = updateProgress 然后,在回调函数里面,使用这个事件的一些属性。 复制代码 代码如下: function updateProgress(event) { if (event.lengthComputable) { var percentComplete = event.loaded / event.total } } 上面的代码中,event.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable不为真,则event.total等于0。 与progress事件相关的,还有其他五个事件,可以分别指定回调函数: * load事件:传输成功完成。 * abort事件:传输被用户取消。 * error事件:传输中出现错误。 * loadstart事件:传输开始。 * loadEnd事件:传输结束,但是不知道成功还是失败。 十、阅读材料 1. Introduction to XMLHttpRequest Level 2: 新功能的综合介绍。 2. New Tricks in XMLHttpRequest 2:一些用法的介绍。 3. Using XMLHttpRequest:一些高级用法,主要针对Firefox浏览器。 4. HTTP Access Control:CORS综述。 5. DOM access control using cross-origin resource sharing:CORS的9种HTTP头信息 6. Server-Side Access Control:服务器端CORS设置。 7. Enable CORS:服务端CORS设置。

参考文章: https://mp.weixin.qq.com/s/Re1fvKKzi-rPpu6SmpqTJA

说到跨域问题,我们最常见的就是在我们向服务器发起请求的时候会遇到。比如说如下情况

假设我们正在访问 https://api.mysebsite.com 的站点,当我们点击按钮,向 https://api.mysebsite/users.com 发送请求,获取网站上的一些用户信息。这个时候从结果上是完美的。原因是,根据 同源策略 ,我们发起请求的 域名 端口 协议 均是一至的。浏览器并不会产生跨域报错。

而如果,以上提到的三点其中一点不满足的站点,再向服务器发起请求,那么这个时候就会触发跨域报错。如下图

而以上两种情况出现的原因,其实就是我们今天要介绍的内容。

首先我们先来介绍一下同源策略

浏览器网络请求的时候,有一个 同源策略 的机制,即默认情况下,使用API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源。也就是我们上面提到的,必须要求域名,端口,协议都要一至。请求才能发送成功。而只要其中一点不一致,那么该请求也算是跨域的。

所以我们同样可以看得出来。同源策略会限制以下三种行为:

说了这么多其实,我们可以看出同源策略的作用其实就是为了保证用户的信息安全。打个比方,如果没有同源策略,那么当你在不小心的情况下,点击了网页的钓鱼网站。然后恶意的网站很容易就能利用重定向把你带到一个iframe 的 攻击网站,这个iframe会自动加载银行网站,并通过Cookie登录你的账号。然后 *** 作你的DOM,进行一系列的危险 *** 作。

而我们当然不希望这种情况发生,这个时候同源策略就起到有效的保护作用。因为它确保了我们只能访问同一站点的资源

好了,接下来要说的就是CORS了。

浏览器出于安全的考虑,会限制 从脚本内发起 的跨域HTTP请求。(注意是脚本内)例如XHR 和 Fetch 就遵循同源策略。这意味着使用 API 的Web应用程序只能从加载应用程序的同一个域请求HTTP资源。

在日常的开发中,我们很多时候都会跨域去请求别的站点的资源。而这个时候我们为了解决跨域的问题就要利用CORS机制。

CORS(Cross-Origin Resource Sharing),即 跨域资源共享 。如字面意思,CORS机制的存在就是为了让我们在保证安全的前提下,实现访问不同域下的资源,这算是放宽的政策。

浏览器可以利用CORS机制,放行一些符合规范的跨域访问,阻止不符合规范的跨域访问。下面我我们就来介绍一下浏览器内部是如何实现的。

Web程序发出跨域请求后,浏览器会 自动 向我们的HTTP header添加一个额外的字段 Origin 。 Origin 标记了请求的站点来源:

为了使浏览器允许访问跨域资源,服务器返回的 response 还需要加一些响应头字段,这些字段可以 显式 的表明此服务器是否允许跨域请求。

作为服务端人员,我们为了允许符合规则的跨域请求。我们可以通过在HTTP的响应中添加响应字段 Access-Control-* 来表明是否允许跨域请求。根据这些CORS响应头字段,浏览器可以允许一些被同源策略限制的跨域响应

虽然有好几个CORS的字段,但是有一个必须要加的字段是 Acess-Control-Allow 。这个头字段的值指定了哪些站点被允许跨域访问资源的。

现在这个字段会被添加到服务端的响应报文中,然后返回给客户端。然后这个时候客户端再向服务端发起跨域请求,同源策略将不会再限制 https://api.mywebsite.com 站点返回的资源。

报文如下:

而相反,如果对比 Access-Control-Allow-Origin 和 Origin 的值不一致的时候,浏览器会抛出一个 CORS Error的报错信息。

除了 Access-Control-Allow-Origin 字段头之外,开发人员还可以通过其他字段对请求作出限制。比如说 Access-Control-Allow-Methods 该字段用来指明跨域请求所允许的 HTTP 方法。

如上图中,只有请求方法为 GET , POST 或 PUT 方法被允许跨域访问资源。其他的HTTP方法,例如 PATCH 和 DELETE 都会产生预检。

这里就引申出一些别的内容,比如说 预检

什么是预检呢?

到这里,CORS和跨域的关系基本就说清楚了。下面我们再说一点补充

XHR 或 Fetch 与 CORS的一个有趣的特性是,我们可以基于 Cookies 和 HTTP 认证信息发送身份凭证。一般而言,对于跨域 XHR 或 Fetch 请求,浏览器 不会 发送身份凭证信息。

尽管 CORS 默认 情况下不发送身份凭证,但我们仍然可以通过添加 Access-Control-Allow-Credentials CORS响应头来更改它

如果要在跨域请求中包含 cookie 和其他授权信息,我们需要做一下 *** 作:

做到了上面几点之后,就能在跨域请求中携带身份凭证了。

以上就是全部内容了

补充参考: http://www.goodpm.net/postreply/csharp/1010000008959813/AccessControlAllowOrigin%E5%A6%82%E4%BD%95%E8%AE%BE%E7%BD%AE%E5%A4%9A%E4%B8%AA%E5%80%BC%E5%91%A2.html


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9939768.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-03
下一篇 2023-05-03

发表评论

登录后才能评论

评论列表(0条)

保存