浏览器跨域的那些事

整理中

目标:

了解跨域

解决跨域

服务器配置跨域(java, nginx)

前端调试时配置解决跨域

一、什么是跨域

当资源请求来自不同域,协议或端口的资源时,资源会发出跨域HTTP请求。出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。例如,XMLHttpRequest并且遵循同源策略。因此,使用XMLHttpRequest提取 的Web应用程序只能向自己的域发出HTTP请求。

什么是同源策略

同源策略是一种关键的安全机制,它限制从一个源加载的文档或脚本如何与来自另一个源的资源交互。

浏览器禁止接收信息的目的是为了防止恶意网站从其他网站读取机密信息,但也阻止网站内容合法读取其他网站提供的信息。

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

举例对比:

http://hotel.jd.com/dir/index.html

url 是否同源 说明
http://hotel.jd.com/dir2/pages.html 同源 仅链接不同
http://hotel.jd.com/dir/pages/index.html 同源 仅链接不同
https://hotel.jd.com/index.html 不同源 协议不同
http://hotel.jd.com:81/pages/index.html 不同源(IE同源) 端口不同
http://train.jd.com/pages/index.html 不同源 子域名不同
http://baidu.com 不同源 主域名不同

【注】IE不包括端口到同源检查。因此,https://company.com:81/index.htmlhttps://company.com/index.html被认为是同源的,没有任何限制。这些异常是非标准的,在任何其他浏览器中都不受支持。

浏览器可以链接跨域资源的html元素:

img、script、css、video、audio、object、embed、applet、@font-face、frame、iframe等。

(1)<img src=""></img>

(2)undefinedundefinedundefined<script src=""></script>标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。jsonp也用到了。

(3) <link src="">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。不同浏览器有不同的限制: IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分 和 Opera。

(4)<video> 和 <audio>嵌入多媒体资源。

(5)<object>, <embed> 和 <applet>的插件。

(6)@font-face引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。

(7) <frame> 和 <iframe>载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。

常见的跨域

接口

main.js:1 Mixed Content: The page at 'https://hotelm-yf.jd.com/coupon' was loaded over HTTPS, but requested an insecure resource 'http://hotel.m.jd.com/api/json/login'. This request has been blocked; the content must be served over HTTPS.

coupon:1 Access to fetch at 'https://hotelm-yf.jd.com/api/wechat/getActivityHotelList' from origin 'http://hotelm-yf.jd.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

[图片上传失败...(image-f3a708-1566981016996)]

[图片上传失败...(image-42aac-1566981016996)]

HTTPS和http跨域提示

[图片上传失败...(image-9c5aa5-1566981016996)]

仅设置了http://hotel.m.jd.comhttps://hotel.m.jd.com时会出现的错误

[图片上传失败...(image-92cc48-1566981016996)]

图片

[图片上传失败...(image-b662f6-1566981016996)]

图片

No 'Access-Control-Allow-Origin' header is present on the requested resource. Originis therefore not allowed access

图片防盗链

会检测访问图片的referer

<meta name="referrer" content="no-referrer" /> 解决

GET https://csdnimg.cn/pubfooter/images/job-QR.png 403

[图片上传失败...(image-51502b-1566981016996)]

  1. 跨站请求正常发起,netWork上可以正常查看,但是结果被浏览器拦截了。

    跨域的iframe

    iframe跨域时仅支持以下JS的api调用

    方法
    window.blur
    window.close
    window.focus
    window.postMessage
    location.replace
    属性
    window.closed 只读
    window.frames 只读
    window.length 只读
    window.location 读/写.
    window.opener 只读
    window.parent 只读
    window.self 只读
    window.top 只读
    window.window 只读

如何阻止跨域

跨域数据存储

浏览器中存储的数据(如localStorage和IndexedDB)的访问按源分开。每个源都有自己的独立存储,一个源中的JavaScript不能从属于另一个源的存储读写。

cookie使用一个单独的起源定义。页面可以为自己的域或任何父域设置cookie,只要父域不是公共后缀。Firefox和Chrome使用公共后缀列表来确定域是否是公共后缀。Internet Explorer使用自己的内部方法来确定域是否是公共后缀。无论使用哪种协议(HTTP/HTTPS)或端口,浏览器都将使cookie对给定域(包括任何子域)可用。设置cookie时,可以使用域、路径、安全和仅http标志限制其可用性。当您读取cookie时,您无法看到它是从何处设置的。即使您只使用安全的https连接,您看到的任何cookie都可能是使用不安全连接设置的。

二、跨域解决的方式

1.跨域资源共享(CORS)

CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource sharing)。它允许浏览器向跨域服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

浏览器限制从脚本内发起的跨域HTTP请求。 例如,XMLHttpRequest和Fetch API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。

跨域资源共享(CORS)机制为Web服务器提供跨域访问控制,从而实现安全的跨域数据传输。现代浏览器在API容器中使用CORS(例如XMLHttpRequestFetch)来缓解跨域HTTP请求的风险。

Access-Control-Allow-Origin

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n143" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Access-Control-Allow-Origin: *</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n144" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">服务器默认是不被允许跨域的。配置Access-Control-Allow-Origin *后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。</pre>

为了保障系统的安全性,不建议设置为通配 * 。并且这种方式浏览器不能携带cookie信息(携带cookie信息只能使用真实域)

Access-Control-Allow-Origin也可指定对应的域名,单个或多个,:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n147" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Access-Control-Allow-Origin: http://test.blyoo.com,https://www.blyoo.com</pre>

Access-Control-Allow-Credentials

响应报头指示的请求的响应是否可以暴露于该页面。当true值返回时它可以被暴露。

Credentials的凭证是 Cookie ,授权标头或 TLS 客户端证书。

当作为对预检请求的响应的一部分使用时,它指示是否可以使用凭证进行实际请求。请注意,简单的GET请求不是预检的,所以如果请求使用凭证的资源,如果此资源不与资源一起返回,浏览器将忽略该响应,并且不会返回到 Web 内容。

Access-Control-Allow-Credentials的 header 文件与该XMLHttpRequest.withCredentials属性或者在提取 API credentialsRequest()构造函数中的选项一起工作。必须在双方(Access-Control-Allow-Credentials的 header 和 XHR 或 Fetch 请求中)设置证书,以使 CORS 请求凭证成功

需要注意的是,在带凭据请求中, Access-Control-Allow-Origin: 头不能是通配符 "*",必须是一个有效的域名。

2.服务端配置:

1.Nginx服务器配置cors

Nginx的配置文件中配置以下参数

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n157" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">add_header Access-Control-Allow-Origin *;</pre>

多个指定域名:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n159" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">add_header Access-Control-Allow-Origin http://test.blyoo.com,https://www.blyoo.com;</pre>

The ‘Access-Control-Allow-Origin’ header contains multiple values, but only one is allowed

The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

代码中查看是不是配置:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n163" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">header("Access-Control-Allow-Origin: *");</pre>

nginx配置有没有配置:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n165" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">add_header Access-Control-Allow-Origin *;</pre>

这两个配置,只要保留一个即可。

列表配置参考

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n168" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">map http_origincorsHost {
default 0;
"~http://www.example.com" http://www.example.com;
"~http://m.example.com" http://m.example.com;
"~http://wap.example.com" http://wap.example.com;
}

server
{
listen 80;
server_name www.example2.com;
root /usr/share/nginx/html;
location /
{
add_header Access-Control-Allow-Origin $corsHost;
}
}</pre>

其它配置参考:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n170" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

if ($request_method = 'OPTIONS') {
return 204;
}
} </pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n172" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">if (http_origin ~* "^http://hotelm-yf.jd.com"){
set cors_originhttp_origin;
}
if (http_origin ~* "^https://hotelm-yf.jd.com"){
set cors_originhttp_origin;
}
if (http_origin ~* "^https://hotel.m.jd.com"){
set cors_originhttp_origin;
}
if (http_origin ~* "^http://hotel.m.jd.com"){
set cors_originhttp_origin;
}
add_header 'Access-Control-Allow-Origin' $cors_origin;</pre>

2.JAVA中配置cors

如果服务端是Java开发的,添加如下设置允许跨域即可,但是这样做是允许所有域名都可以访问,不够安全。并且这种方式浏览器不能携带cookie信息(携带cookie信息只能使用真实域)。这种方式只推荐在不带cookie信息的开发中测试使用。代码如下:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n177" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">response.setHeader("Access-Control-Allow-Origin","*");</pre>

为保证安全性,可以只添加部分域名允许访问,添加位置可以在下面三处任选一个。

(1)可以在过滤器的filter的dofilter()方法种设置。

(2)可以在servlet的get或者post方法里面设置。

(3)可以放在访问的jsp页面第一行。

使用dofilter()的Demo

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="true" cid="n183" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
// 将ServletResponse转换为HttpServletResponse
HttpServletResponse httpResponse = (HttpServletResponse) res;
// 如果不是80端口,需要将端口加上,如果是集群,则用Nginx的地址,同理不是80端口要加上端口
String [] allowDomain= {"http://www.baidu.com","http://123.456.789.10","http://123.16.12.23:8080"};
Set allowedOrigins= new HashSet(Arrays.asList(allowDomain));
String originHeader=((HttpServletRequest) req).getHeader("Origin");
if (allowedOrigins.contains(originHeader)){
httpResponse.setHeader("Access-Control-Allow-Origin", originHeader);
httpResponse.setContentType("application/json;charset=UTF-8");
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
// 如果要把Cookie发到服务器,需要指定Access-Control-Allow-Credentials字段为true
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Expose-Headers", "*");
}
chain.doFilter(req, res);
} </pre>

3.PHP配置cors

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="php" contenteditable="true" cid="n185" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">//如果需要设置允许所有域名发起的跨域请求,可以使用通配符 *
<?php
header("Access-Control-Allow-Origin: *");
?>

//单个
<?php
header("Access-Control-Allow-Origin: www.xxx.xom");
?>

//多个
<?php
origin = 'https://www.google.com,https://www.baidu.com'; header('Access-Control-Allow-Origin:' .origin);
?>

//多个
<?php
allowed_origins = array( "http://www.aaa.com" , "http://app.bbb.com" , "http://cms.ccc.com" , ); if (in_array(_SERVER['HTTP_ORIGIN'], allowed_origins)){ @header("Access-Control-Allow-Origin: " ._SERVER['HTTP_ORIGIN']);
}
?></pre>

4.apache配置cors

在httpd配置或.htaccess文件中添加如下语句

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n188" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">SetEnvIf Origin "^(.*.example.com)" ORIGIN_SUB_DOMAIN=1
Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN</pre>

或apache下修改vhosts中根域名的配置:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="php" contenteditable="true" cid="n190" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><Directory "/Users/cindy/dev">
AllowOverride ALL
Header set Access-Control-Allow-Origin https://www.google.com,https://www.baidu.com
</Directory></pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n191" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><VirtualHost *:80>
Header add Access-Control-Allow-Origin *
Header add Access-Control-Allow-Methods "GET, POST, OPTIONS"
Header add Access-Control-Allow-Headers "Content-Type"
<Directory myhtdocsdir>
AllowOverride All
</Directory>
</VirtualHost></pre>

3.前端配置

如仅需要获取接口返回数据,服务端配置好 Access-Control-Allow-Origin 前端即可获取到后端返回的数据了。当跨域还需要传递凭证cookie时。需要在请求时配置Credentials为true。

配置Credentials

以下是前端用各种方式请求时设置Credentials的方式。

1.XHR设置credetials

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="js" contenteditable="true" cid="n197" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null);</pre>

2.Fetch设置携带credentials

默认情况下,fetch 不会从服务端发送或接收任何 cookies, 如果站点依赖于用户 session,则会导致未经认证的请求(要发送 cookies,必须设置 credentials 选项)

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="js" contenteditable="true" cid="n200" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">fetch(url, {
credentials: 'include'
})</pre>

cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached ​ credentials: 'same-origin', // include, same-origin, *omit

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

3.axios设置credentials

设置axios.defaults.withCredentials

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n205" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import axios from 'axios'
axios.defaults.withCredentials = true</pre>

单独设置

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n207" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">axios({
method: 'get',
url: 'XXX',
withCredentials: true
})</pre>

4.vue-resource设置credentials

以下为全局引用vue的demo。非全局引用的参考参数传递。原理一致

VUE官方推荐使用axios ,vue-resource不更新了

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n211" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import vue from 'vue'
vue.http.get(url,{
credentials: true
},{
emulateJSON: true
})
​</pre>

  1. 一定要设置 {emulateJSON: true},不然跨域不成功.
5.jQuery ajax设置credentials

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="js" contenteditable="true" cid="n216" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">$.ajax({
url : 'http://hotel.m.jd.com/api/login',
data : data,
dataType: 'json',
type : 'POST',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json",
​</pre>

四、前端调试跨域

webpack配置接口地址代理

启动服务器后,本地开发服务下 http://localhost:8080 ,接口地址是 http://www.xxx.com/api/,就会存在跨域的请求,导致接口请求不成功。

webpack自带代理功能,通过以下配置。可以将接口地址代理的方式映射到本地。

解决开发环境的跨域问题(不用在去配置nginx和host)

在webpack.config.js中配置

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n224" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">​</pre>

webpack代理参考:https://webpack.js.org/configuration/dev-server/#devserver-proxy

whistle修改请求头解决跨域

No 'Access-Control-Allow-Origin' header is present on the requested resource

2.jsonp

3.doucument.domain

用document.domain来指定域,主要解决的是子域与父域之间的跨域。

如: hotel.m.jd.com、train.m.jd.com 指定到m.jd.com

4.postMessage()

postMessage()允许来自不同源的脚本采用异步方式进行通信,可以实现跨域消息传递。 postMessage(data,origin) data:要传递的数据 origin:指明目标窗口的源。协议主机端口号 接收消息:监听window的message事件,包括 data——传递过来的message source——发送消息的窗口对象 origin——发送消息窗口的源

5.location.hash

6.script篇

7.window.name

window.name 传输技术,原本是 Thomas Frank 用于解决 cookie 的一些劣势(每个域名 4 x 20 Kb的限制、数据只能是字符串、设置和获取 cookie 语法的复杂等等)而发明的。后来 Kris Zyp 在此方法的基础上强化了 window.name 传输 ,用来解决跨域数据传输问题。

window.name 的美妙之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" contenteditable="true" cid="n242" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 1em 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">在A域名下设置window.name,通过href跳转至目标页。 再获取window.name的参数
例:
A页面
window.name = '跨域的参数'
<a id="al" href="http://www.lamport.me/data.html">点击我跨域传值</a>
B页面
window.name //跨域的参数
​</pre>

参考文献

  1. 同源策略https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy

    https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

  2. HTTP访问控制(CORS)https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

  3. Server-Side Access Controlhttps://developer.mozilla.org/zh-CN/docs/Web/HTTP/Server-Side_Access_Control

  4. XY博客https://www.cnblogs.com/sunmmi/articles/5956554.html

  5. Fetch https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

  6. webpack proxy:https://webpack.js.org/configuration/dev-server/#devserver-proxy

crossorigin = "anonymous"

七种跨域方法【2.document.domain篇】

​​

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

推荐阅读更多精彩内容

  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    Yaoxue9阅读 1,271评论 0 6
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    他方l阅读 1,056评论 0 2
  • 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实...
    HeroXin阅读 819评论 0 4
  • 欢迎关注微信公众号:全栈工厂 本文主要参考跨域资源共享 CORS 详解[http://www.ruanyifeng...
    liqingbiubiu阅读 1,796评论 0 3
  • 题目1.什么是同源策略? 同源策略(Same origin Policy): 浏览器出于安全方面的考虑,只允许与本...
    FLYSASA阅读 1,701评论 0 6