js의 도메인 간 방법

小云云
풀어 주다: 2017-12-09 16:58:24
원래의
1469명이 탐색했습니다.

oneday-music-player를 만들 때 ajax를 사용하여 Baidu Music의 API에 요청을 보내야 하는데 XMLHttpRequest가 'http://....'를 로드할 수 없습니다. 아니요 'Access-Control-Allow-Origin' 요청 리소스에 'http://....'라는 헤더가 있어서 접근이 허용되지 않습니다. 검색 결과 동일한 출처 정책으로 인한 크로스 도메인 문제인 것으로 확인되었습니다. 도메인 간 지식에 대해.

동일 원본 정책

동일 원본 정책은 한 소스에서 로드된 문서 또는 스크립트가 다른 소스의 문서 또는 스크립트와 상호 작용하는 방식을 제한하고 잠재적으로 악성 파일을 격리하는 중요한 보안 메커니즘입니다.

두 페이지의 프로토콜, 포트(지정된 경우) 및 도메인 이름이 동일한 경우 두 페이지의 출처가 동일하다고 할 수 있습니다.

다음 표는 <code><span style="font-size: 14px;">http://store.company.com/dir/page.html</span>同源检测的示例:

url 结果 原因
<span style="font-size: 14px;">http://store.company.com/dir2/other.html</span> 成功
<span style="font-size: 14px;">http://store.company.com/dir/inner/other.html</span> 成功
<span style="font-size: 14px;">https://store.company.com/secure.html</span> 失败 不同协议(<span style="font-size: 14px;">https</span><span style="font-size: 14px;">http</span>
<span style="font-size: 14px;">http://store.company.com:81/dir/etc.html</span> 失败 不同端口(81和80)
<span style="font-size: 14px;">http://news.company.com/dir/other.html</span> 失败 不同域名(<span style="font-size: 14px;">news</span><span style="font-size: 14px;">store</span>http://store.company.com/dir/page.html에 대한 동일 출처 감지의 예입니다.
url
🎜result🎜 🎜reason🎜🎜 🎜http://store.company.com/dir2/other.html🎜🎜 🎜Success🎜🎜🎜 🎜http://store.company.com/dir/inner/other.html🎜🎜 🎜Success🎜🎜🎜 🎜https: //store .company.com/secure.html🎜🎜 🎜failed🎜🎜 🎜다른 프로토콜(🎜🎜https🎜🎜 및 🎜🎜http 🎜 code>🎜)🎜🎜🎜<tr> <td> <code>🎜http://store.company.com:81/dir/etc.html🎜🎜 🎜실패🎜🎜 🎜다른 포트(81 및 80)🎜🎜🎜 🎜http://news.company.com/dir/other.html🎜🎜 🎜실패 🎜🎜🎜다른 도메인 이름(🎜🎜news🎜🎜 및 🎜🎜store🎜🎜)🎜🎜🎜🎜🎜

동일한 출처가 아닌 경우 세 가지 동작이 제한됩니다.

  • Cookie, LocalStorage 및 IndexDB를 읽을 수 없습니다.

  • DOM을 얻을 수 없습니다.

  • AJAX 요청을 할 수 없습니다. be sent

동일 출처 정책 방지(도메인 간)

Cookie

<span style="font-size: 14px;">document.domain</span>

쿠키는 서버가 브라우저에 작성한 작은 정보 조각으로, 같은 병원의 웹페이지에서만 공유할 수 있습니다. 그러나 두 웹페이지의 1차 도메인 이름은 동일하지만 2차 도메인 이름은 다릅니다. 브라우저에서는 <code><span style="font-size: 14px;">document.domain</span>共享Cookie

例如,假设文档中的一个脚本在<code><span style="font-size: 14px;">http://store.company.com/dir/page.html</span>执行以下语句:

<span style="font-size: 14px;">document.domain = "company.com"<br></span>
로그인 후 복사

此时,<span style="font-size: 14px;">http://news.company.com/dir/other.html</span><span style="font-size: 14px;">http://store.company.com/dir/other.html</span>
就可以通过<span style="font-size: 14px;">document.cookie</span>来设置或获取Cookie,即共享Cookie。

但是这种方法适用于Cookie和iframe窗口,LocalStorage和IndexDB无法通过这种方法规避同源策略。

<span style="font-size: 14px;">iframe</span>

如果两个网页不同源,就无法拿到对方的DOM,典型的例子是<span style="font-size: 14px;">iframe</span>窗口和<span style="font-size: 14px;">window.open</span>方法打开的窗口,如果和父窗口不同源,则会报错。

此时如果两个窗口一级域名相同,只是二级域名不同,那么设置<code><span style="font-size: 14px;">document.domain</span>属性,就可以规避同源策略。

而对于完全不同源的网站,目前有三种方法可以解决跨域窗口之间的通信问题。

  • 片段标识符(fragment identifier)

  • <span style="font-size: 14px;">window.name</span>

  • 跨文档通信API(cross-document messaging)

片段标识符

片段标识符(fragment identifier)指的是URL的#后面的部分,即<span style="font-size: 14px;">http://store.company.com/dir/other.html#fragment</span><span style="font-size: 14px;">#fragment</span>(location.hash),如果只改变片段标识符,页面不会重新刷新。

父窗口可以把信息写入子窗口的片段标识符,子窗口通过监听<span style="font-size: 14px;">hashchange</span>事件得到通知。

<span style="font-size: 14px;">window.name</span>

每个iframe都有包裹它的window,这个window是top window的子窗户,所以自然有<span style="font-size: 14px;">window.name</span>document.domain

을 통해 쿠키를 공유할 수 있습니다. 예를 들어 문서의 스크립트가

🎜http://store.company.com/dir/page.html🎜🎜에 있다고 가정합니다. 다음 문을 실행합니다. 🎜🎜
<span style="font-size: 14px;">var newWin = window.open('http://company.com/data.html', 'title')<br>newWin.postMessage('Hello World!'. 'http://company.com/data.html')<br></span>
로그인 후 복사
로그인 후 복사
🎜🎜여기서 시간, 🎜🎜http://news.company.com/dir/other.html🎜🎜 및 🎜🎜http://store.company.com/dir/other.html🎜
🎜 🎜🎜document.cookie🎜🎜를 전달하여 쿠키, 즉 공유 쿠키를 설정하거나 가져올 수 있습니다. 🎜🎜🎜🎜그러나 이 방법은 Cookie 및 iframe 창에서 작동하므로 LocalStorage 및 IndexDB는 이 방법을 통해 동일한 원본 정책을 우회할 수 없습니다. 🎜🎜🎜🎜iframe🎜🎜🎜🎜두 웹 페이지의 소스가 서로 다르면 서로의 DOM을 얻을 수 없습니다. 일반적인 예는 🎜🎜iframe🎜🎜window 및 🎜🎜window.open입니다. 🎜🎜 🎜 메서드로 열린 창의 소스가 상위 창과 다른 경우 오류가 보고됩니다. 🎜🎜🎜🎜이때 두 창의 1차 도메인 이름은 동일하지만 2차 도메인 이름이 다른 경우에는 🎜🎜document.domain🎜🎜을 설정합니다. 속성은 동일 출처 정책을 우회할 수 있습니다. 🎜🎜🎜🎜출처가 완전히 다른 웹사이트의 경우 현재 크로스 도메인 창 간의 통신 문제를 해결하는 세 가지 방법이 있습니다. 🎜🎜🎜🎜🎜🎜조각 식별자🎜🎜🎜🎜🎜🎜window.name🎜🎜🎜🎜🎜🎜문서 간 메시징 API(문서 간 메시징)🎜🎜🎜🎜🎜🎜 🎜🎜🎜 🎜조각 식별자는 URL에서 # 뒤의 부분, 즉 🎜🎜http://store.company.com/dir/other.html#fragment🎜🎜의 🎜🎜#fragment🎜 code>🎜(location.hash), 조각 식별자만 변경되면 페이지가 새로 고쳐지지 않습니다. 🎜🎜🎜🎜부모 창은 자식 창의 조각 식별자에 정보를 쓸 수 있으며, 자식 창은 🎜🎜hashchange🎜🎜 이벤트를 수신하여 알림을 받습니다. 🎜🎜🎜🎜window.name🎜🎜🎜🎜각 iframe에는 자신을 감싸는 창이 있습니다. 이 창은 상단 창의 하위 창이므로 당연히 🎜🎜window.name🎜🎜을 갖습니다. 현재 창의 이름을 가리키는 속성입니다. 이 속성의 가장 큰 특징은 소스가 동일하든 아니든 동일한 창에 있으면 해당 창의 모든 페이지를 읽습니다. window.name에 대한 쓰기 권한이 있습니다. 🎜🎜🎜🎜window.name의 값은 문자열 형식만 가능합니다. 이 문자열의 최대 용량은 브라우저에 따라 약 2M 이상이 될 수 있습니다. 🎜🎜

例如,想要在<span style="font-size: 14px;">http://example/a.html</span>中获取<span style="font-size: 14px;">http://company.com/data.html</span>中的数据,可以在a.html中使用一个隐藏的iframe,将iframe的src首先设置为<span style="font-size: 14px;">http://company.com/data.html</span>,将其window.name设置为所需的数据内容,随后再将这个iframe的src设置为跟a.html页面同一个域的一个页面,不然a.html获取不到该iframe的window.name

<span style="font-size: 14px;">window.postMessage</span>

这是html5中新引入的一个API,可以使用它向其它的window对象发送消息,无论这个window对象属于同源还是不同源。

例如,父窗口<span style="font-size: 14px;">http://example/a.html</span>向子窗口<span style="font-size: 14px;">http://company.com/data.html</span>发送消息:

<span style="font-size: 14px;">var newWin = window.open('http://company.com/data.html', 'title')<br>newWin.postMessage('Hello World!'. 'http://company.com/data.html')<br></span>
로그인 후 복사
로그인 후 복사

<span style="font-size: 14px;">window.postMessage</span>方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,即<span style="font-size: 14px;">协议</span>+<span style="font-size: 14px;">端口</span>+<span style="font-size: 14px;">域名</span>,也可以设置为<span style="font-size: 14px;">*</span>,表示不限制域名。

子窗口向父窗口发送消息的写法类似:

<span style="font-size: 14px;">window.opener.postMessage('Nice to see you', 'http://example/a.html')<br></span>
로그인 후 복사

子窗口和父窗口都可以通过<span style="font-size: 14px;">message</span>时间,监听对方的消息。

<span style="font-size: 14px;">window.addEventListener('message', function(e) {<br>    // ...<br>}, false)<br></span>
로그인 후 복사

<span style="font-size: 14px;">message</span>事件的事件对象<span style="font-size: 14px;">event</span>有以下三个属性:

  • event.source: 发送消息的窗口

  • event.origin: 消息发向的网址(可以限制目标网址)

  • event.data: 消息内容

通过<span style="font-size: 14px;">window.postMessage</span>,也可以读写其他窗口的<span style="font-size: 14px;">localStorage</span>

AJAX

同源策略规定,AJAX请求只能发给同源的网址,否则就报错,但是有三种方法可以规避这个限定:

  • JSONP

  • WebSocket

  • CORS

JSONP

JSONP是服务器与客户端跨源通信的常用方法。基本思想是利用<span style="font-size: 14px;"><script></span>请求脚本能够跨域访问的特性,先定义了一个回调方法,然后将其作为url参数的一部分发送到服务端,服务端通过字符串拼接的方式将数据包裹在回调方法中,再返回回来。

<span style="font-size: 14px;">// 网页动态插入`<script>`元素<br>function addScriptTag(src) {<br>    var script = document.createElement("script")<br>    script.setAttribute("type", "text/javascript")<br>    srcipt.src = src<br>    document.body.appendChild(script)<br>}<br><br>window.onload = function() {<br>    addScriptTag('http://example.com/ip?callback=foo')<br>}<br><br>function foo(data) {<br>    // ...<br>}<br></span>
로그인 후 복사

WebSocket

WebSocket是一种通信协议,使用<span style="font-size: 14px;">ws://</span>(非加密)和<span style="font-size: 14px;">wss://</span>(加密)作为协议前缀。该协议不实行同源政策,只要服务支持,就可以通过它进行跨源通信。

浏览器发出的WebSocket请求的头信息中含有<span style="font-size: 14px;">Origin</span>字段,表示该请求的请求源,即发自哪个域名。(加入白名单)

CORS

跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种使用额外的HTTP头来使一个用户代理从一个不同于当前站点(域)的服务器获取指定的资源的机制。用户代理使用跨域HTTP请求来获取与当前文档不同域、不用协议或端口的资源。

出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求。而跨域资源共享(CORS)机制允许web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在API容器中(例如<span style="font-size: 14px;">XMLHttpRequest</span><span style="font-size: 14px;">Fetch</span>)使用CORS,以降低跨域HTTP请求所带来的风险。

跨域资源共享标准允许在下列场景中使用跨域HTTP请求:

  • 由XMLHttpRequest或Fetch发起的跨域HTTP请求;

  • web字体(CSS中通过<span style="font-size: 14px;">@font-face</span>使用跨域字体资源),因此,网站就可以发布TrueType字体资源,并只允许已授权网站进行跨站调用;

  • WebGL贴图;

  • 使用drawImage将Images/video画面绘制到canvas;

  • 样式表(使用CSSOM);

  • Scripts(未处理的异常)。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)

只要同时满足以下两大条件,就属于简单请求:

1 请求方法是以下三种方法之一:

<span style="font-size: 14px;">- HEAD<br>- GET<br>- POST<br></span>
로그인 후 복사

2 HTTP的头信息不超出以下几种字段:

<span style="font-size: 14px;">- Accept<br>- Accept-Language<br>- Content-Language<br>- Last-Event-ID<br>- Content-Type:(只限三个值:application/x-www-form-urlencoded、multipart/from-data、text/plain)<br></span>
로그인 후 복사

只要不同时满足上面两个条件,就属于非简单请求

简单请求

对于简单请求,浏览器会在请求头部增加一个<span style="font-size: 14px;">Origin</span>字段。这个字段用来说明本次请求来自哪个源(协议+域名+端口)。服务器根据这个值决定是否同意这次请求。

如果<span style="font-size: 14px;">Origin</span>指定的源不在许可范围内,服务器会返回一个正常的HTTP回应。而这个回应的头信息不包含<span style="font-size: 14px;">Access-Control-Allow-Origin</span>字段,从而会抛出错误被<span style="font-size: 14px;">XMLHttpRequest</span><span style="font-size: 14px;">onerror</span>函数捕获,(回应的状态码有可能是200)。

如果<span style="font-size: 14px;">Origin</span>指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段

<span style="font-size: 14px;">Access-Control-Allow-Origin: ...<br>Access-Control-Allow-Credentials: true<br>Access-Control-Expose-Headers: callback<br>Content-Type: text/html; charset=utf-8<br></span>
로그인 후 복사
  • <span style="font-size: 14px;">Access-Control-Allow-Origin</span>: 必须。值要么是请求时<span style="font-size: 14px;">Origin</span>的值,要么是'*'

  • <span style="font-size: 14px;">Access-Control-Allow-Credentials</span>: 可选。布尔值,决定是否允许发送Cookie,不需要则删除该字段。

  • <span style="font-size: 14px;">Access-Control-Expose-Headers</span>: 可选。CORS请求时,<span style="font-size: 14px;">XMLHttpRequest</span>对象的 <span style="font-size: 14px;">getResponseHeader()</span>方法只能拿到6个基本字段:<span style="font-size: 14px;">Cache-Control</span><span style="font-size: 14px;">Content-Language</span><span style="font-size: 14px;">Content-Type</span><span style="font-size: 14px;">Expires</span><span style="font-size: 14px;">Last-Modified</span><span style="font-size: 14px;">Pragma</span>。如果想拿到其他字段,就需要在<span style="font-size: 14px;">Access-Control-Expose-Header</span>里面指定。上面的例子指定为callback,则可以使用<span style="font-size: 14px;">getResponseHeader(callback)</span>获取callback字段的值。

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发送到服务器,一方面要服务器同意,指定<span style="font-size: 14px;">Access-Control-Allow-Credentials</span>字段,另一方面,开发者需要在AJAX请求中设置<span style="font-size: 14px;">withCredentials</span>属性:

<span style="font-size: 14px;">var xhr = new XMLHttpRequest()<br>xhr.withCredentials = true<br></span>
로그인 후 복사

否则,即使服务器同意发送Cookie,浏览器也不会发送。

需要注意的是,如果要发送Cookie,<span style="font-size: 14px;">Access-Control-Allow-Origin</span>就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源策略,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且跨域的原网页中的<span style="font-size: 14px;">document.cookie</span>操作也无法获取嗷服务器域名下的Cookie。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是<span style="font-size: 14px;">PUT</span><span style="font-size: 14px;">DELETE</span>,或者<span style="font-size: 14px;">Content-Type</span>字段的类型是<span style="font-size: 14px;">application/json</span>

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP操作和头信息字段。只有得到肯定答复,浏览器才会发出正式的<span style="font-size: 14px;">XMLHttpRequest</span>请求,否则就报错。

“预检”请求用请求方法是<span style="font-size: 14px;">OPTIONS</span>,表示这个请求是用来询问的。头信息里面,关键字段是<span style="font-size: 14px;">Origin</span>,表示请求来自哪个源。

还有以下两个特殊字段:

  • <span style="font-size: 14px;">Access-Control-Request-Method</span>: 必须。列出非简单请求的请求类型

  • <span style="font-size: 14px;">Access-Control-Request-Headers</span>: 非简单请求额外携带的头信息字段。

服务器返回的响应:

<span style="font-size: 14px;">Access-Control-Allow-Methods: ...<br>Access-Control-Expose-Headers: callback<br>Access-Control-Allow-Credentials: true<br>Access-Control-Max-Age: 1728000<br></span>
로그인 후 복사
  • Access-Control-Allow-Methods: 必须。逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。为了避免多次“预检”行为。

  • Access-Control-Expose-Headers: 브라우저 요청에 <span style="font-size: 14px;">Access-Control-Request-Headers</span>字段,则<span style="font-size: 14px;">Access-Control-Allow-Headers</span>字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

  • Access-Control-Allow-Credentials: 与简单请求时的含义相同。

  • Access-Control-Max-Age: 本次预检请求的有效期。

CORS与JSONP的比较

CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持<span style="font-size: 14px;">GET</span>Access-Control-Request-Headers 필드가 포함된 경우

<p>Access-Control-Allow- 헤더 <span style="font-size: 14px;"></span></p> 필드는 필수입니다. 또한 "preflight"에서 브라우저가 요청한 필드에 국한되지 않고 서버가 지원하는 모든 헤더 필드를 나타내는 쉼표로 구분된 문자열이기도 합니다.

Access-Control-Allow-Credentials: 간단한 요청과 동일한 의미를 갖습니다.

Access-Control-Max-Age: 이 실행 전 요청의 유효 기간입니다.

CORS와 JSONP의 비교

🎜🎜CORS는 JSONP와 동일한 목적을 가지고 있지만 JSONP보다 더 강력합니다. 🎜🎜🎜🎜JSONP는 🎜🎜GET🎜🎜 요청만 지원하고 CORS는 모든 유형의 HTTP 요청을 지원합니다. JSONP의 장점은 이전 브라우저를 지원하고 CORS를 지원하지 않는 웹사이트에서 데이터를 요청할 수 있다는 것입니다. 🎜🎜🎜🎜관련 권장 사항: 🎜🎜🎜🎜🎜Js를 사용하여 지연 로딩 및 교차 도메인을 구현하는 단계🎜🎜🎜🎜🎜Js 교차 도메인을 이해하는 방법🎜🎜🎜🎜laravel의 교차 도메인 기능을 활성화하는 방법을 설명하세요🎜🎜 🎜🎜

위 내용은 js의 도메인 간 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿