liujie2019/Blog

ajax跨域完全讲解

Opened this issue · 0 comments

1. 产生跨域问题的原因

  1. 浏览器限制(出去安全原因)
  2. 跨域
  3. XHR请求

2. 解决思路

image

  1. 浏览器限制(基于同源策略的安全检查),取消安全检查;
  2. jsonp:实现jsonp、不好用(让发出的请求变为不是XHR的类型);
  3. xhr:两种方法 一种:被调方(修改服务器,支持跨域)。第二种:调用方,通过实现代理的方式(隐藏跨域)。
2.1 浏览器禁止检查:命令行参数启动
  1. 终端输入:C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security
  2. 如果方法1不行,通过everyting软件找到chrome.exe所在的路径,在chrome.exe所在的路径按下shift键,点击右键,点击“在此处打开命令行窗口”,然后输入chrome --disable-web-security
chrome --disable-web-security --user-data-dir=g:\temp3
2.2 jsonp(JSON with Padding)

jsonp返回的是js代码,不是json对象。

  • content-type:发送信息至服务器时内容编码类型,即客户端发送请求数据的类型;
  • ajax的属性添加cache:true,表示结果可以被缓存,请求的链接中就没有_=某个值;

jsonp的弊端:

  1. 需要服务器改动代码;
  2. 只支持GET请求;
  3. 发送的不是xhr请求。

image

jsonp方式发出的请求为script类型。

image

客户端->http服务器->应用服务器,然后从,应用服务器->http服务器->客户端。

image

Apache/nginx为http静态服务器,用来处于静态请求或者负载均衡。

2.3 被调用方解决-支持跨域

image

跨域请求和非跨域请求的区别:跨域请求的请求头中多了Origin字段,即当前域名。
image

表示允许所有的域名和方法。

2.4 简单请求和非简单请求
  1. 简单请求:先执行后检测;
  2. 非简单请求:先预检,后执行。
  3. OPTIONS:预检命令
  4. OPTIONS缓存:Access-Control-Max-Age指定缓存预检请求的时间。

非简单请求每次都要发送两条请求,效率很低,可以通过将预检请求缓存来减少请求数量,设置方法是服务端响应头设置Access-Control-Max-Age,值是预检请求缓存时间,如下所示:

// 缓存预检请求1个小时
"Access-Control-Max-Age": "3600"

image
image

2.5 带Cookie的跨域
$.ajax({
    type: "get",
    xhrFields: {
        widthCredentials: true // 发送ajax请求的时候会带上cookie
    }
})
  1. cookie是加在被调用方;
  2. 读cookie只能读到本域的。

不允许设置:Access-Control-Allow-Origin: *;,必须指定为特定的域名。

// enable cookie
res.addHeader("Access-Control-Allow-Credentials", "true")

当产生跨域的时候,请求头中会多一个字段,叫做origin,这个字段存储着当前域的信息。所以在发送带cookie的请求,后台又不知道调用方的域的信息时,可以先取到请求头中origin字段的值,然后再赋值给响应头的access-control-allow-origin字段。
image

2.6 带自定义头的跨域

image

2.7 被调用方解决跨域-nginx解决方案

虚拟主机:多个域名指向同一个服务器,服务器根据不同的域名把请求转到不同的应用服务器。看上去有多个主机,实际上只有一个主机。

nginx配置:

server {
    listen 80; // 监听的端口
    server_name b.com; // 监听的域名
    // 所有的请求都转发到这个地址
    location /{
        proxy_pass http://localhost:8080/;
    }
}

image

nginx配置跨域:

server {
    listen 80; // 监听的端口
    server_name b.com; // 监听的域名
    // 所有的请求都转发到这个地址
    location /{
        proxy_pass http://localhost:8080/;
    }
}
2.8 被调用方解决跨域-apache解决方案

image

2.9 调用方解决跨域-隐藏跨域

反向代理:访问同一个域名的不同url,最后去到两个不同的服务器。

反向代理-nginx配置:

image

反向代理-apache配置:

image
image

当前请求地址:

image

参考文档

  1. Nginx 解决API跨域问题