跨域及解决方案

跨域及解决方案

  • jsonp(常用)

  • cors(常用)

  • window.name

  • document.domain(特定场景)

  • postMessage(H5)

  • webpack proxy (webSocket)(常用)

  • ngix方向代理

1. 什么是跨域

拿当前HTML页面的地址和在页面中Ajax请求的API地址做比较:

    1. 如果两个地址的协议域名端口号都相同,相当于HTML页面从同一个源下根据某个地址获取数据,属于同源策略请求,基于ajax是可以直接请求到数据的

    2. 如果协议,域名,端口号三种只要有一个不一样,那么就是非同源策略请求(跨域请求),使用ajax不能直接获取数据了

2. 跨域存在的普遍性

现在的项目一般都是前后端分离的,公司一般都会把后台程序用一个服务器管理,客户端程序有一个新的服务器管理,两个服务不是同一个源,这样就导致客户端是想其他源发送ajax请求,跨域成为请求的阻碍问题

3. 解决方案

3.1 JSONP

在客户端ajax不允许直接的跨域请求,但是很多东西是可以直接的跨域,比如:scriptlinkimgiframe等(这些标签的src或者href设置任何一个资源请求地址,哪怕是其他源下的,也都没有跨域的限制,直接可以把内容获取到【除非服务器做特殊处理了】)=>针对这个特点,真实项目中某些JS文件加载的都是CDN地址

3.2 CORS 跨域资源共享

主要是服务器设置,配置允许跨域的相关头部信息

 //=>基于CORS设置允许跨域请求
 app.use((req, res, next) => {
     //=>允许哪些源可以向这个服务发送AJAX请求(通配符是允许所有的源,也可以单独设置某个源 "http://localhost:8000/"这样就是只允许8000服务过来请求) =>不使用通配符是为了保证接口和数据的安全,不能让所有的源都能访问;而且一旦设置了允许携带凭证过来,则设置*会被报错,此时只能设置具体的源!只能设置单一一个允许访问的源!
     res.header("Access-Control-Allow-Origin", "http://localhost:8000");
 ​
     //=>是否允许跨域的时候携带凭证(例如:COOKIE就是凭证的一种,设置为FALSE,客户端和服务器之间不会传递COOKIE,这样SESSION存储就实效了)
     res.header("Access-Control-Allow-Credentials", true);
 ​
     //=>允许的请求头部
     res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
 ​
     //=>允许的请求方式(OPTIONS一定要有)
     res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
 ​
     //=>设置OPTIONS请求目的:我们把这个请求当做一个试探性请求,当客户端需要向服务器发送请求的时候,首先发送一个OPTIONS请求,服务器接收到是OPTIONS请求后,看一下是否允许跨域,允许返回成功,如果服务器不允许跨域,则客户端会出现跨域请求不允许的错误;如果客户端检测到不允许跨域,则后续的请求都不在进行!  =>客户端AXIOS框架就是这样处理的
     if (req.method === 'OPTIONS') {
         res.send('OK!');
         return;
     }
 ​
     next();
 });
 ​

客户端:

axios在某些特定场景下,在发送真实请求之前都会发送一个请求(options)格式的来验证是否允许跨域

 axios.defaults.widthCredentials=true
 //xhr.widthCredentials=true

弊端:

只能指定一个允许源(不能用通配符和指定多个源),所以目前真实项目中基于CORS实现跨域资源共享是主流方案

3.3 webpack代理(webpack proxy)

    1. 安装webpack-dev-server

    2. 配置代理

     proxy:{
         '/api':{
             targer:'https://localhost:8080/',
             chanageOrigin:true,
             secure:false,
             pathRewrite:{
                 '^/api':''
             }    
         },
         '/getInfo':{
             target:'https://localhost:8080/',
             chanageOrigin:true    
         }    
     }

3.4 ngnix反向代理

3.5 node作为中间件代理

3.6 基于iframe跨域

iframe可以实现父页面嵌入子页面(父页面中可以基于js获取子页面中的内容)

    1. window.name:name是window天生自带的属性,而且有一个特点,同源下,找x页面中设置name的值,页面关掉或者刷新,上次设置的值不消失,能够一直存储最后一次修改的值信息

    2. document.domian:只能处理主域相同,但是子域不同的情况

    3. postMessage

你可能感兴趣的:(JS)