Skip to content
On this page

跨域

跨域解决方案:

  1. jsonp (常用)
  2. cors (常用)
  3. window.name
  4. document.domain (特定场景)
  5. postMessage (H5)
  6. webpack proxy (webScoket) (常用)
  7. ngix 反向代理 ...

什么是跨域?

拿当前 HTML 页面的地址和在页面中 AJAX 请求的 API 地址做比较: 如果两个地址的协议域名端口号都相同,相当于 HTML 页面从同一个源下根据某个地址获取数据,属于“同源策略请求”,基于 AJAX 是可以直接请求到数据的! 如果三者(协议域名端口号)只要有一个不一样,那么就是“非同源策略请求(跨域请求)”,使用 AJAX 不能直接获取数据了!

HTML 页面的地址:http://localhost:8000/A.html AJAX 请求的地址:http://localhost:8000/queryInfo

HTML 页面地址:http://localhost:63342/201802LESSON/%E5%85%AC%E5%BC%80%E8%AF%BE/%E8%B7%A8%E5%9F%9F/static/A.html AJAX 请求接口地址:http://localhost:8000/queryInfo

【报错】

Failed to load http://localhost:8000/queryInfo: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access.

跨域的普遍性?

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

同源:把客户端程序和服务器程序在一个服务中发布!

=======================================

方案一:JSONP

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

方案二:CORS 跨域资源共享

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

javascript
    app.use((req, res, next) => {
        res.header("Access-Control-Allow-Origin", "http://localhost:8000");
        res.header("Access-Control-Allow-Credentials", true);
        res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
        res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
        if (req.method === 'OPTIONS') {
            res.send('OK!');
            return;
        }
        next();
    });
1
2
3
4
5
6
7
8
9
10
11

客户端

javascript
  axios.defaults.withCredentials = true;
  //=>xhr.withCredentials=true

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

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

方案三:WEBPACK 代理(webpack proxy)

1. 安装 webpack-dev-server
2. 配置代理:
proxy: {
  '/api': {
    target: 'https://other-server.example.com',
    changeOrigin: true,
    secure: false,
    pathRewrite: {
       '^/api' : ''
    }
  },
  '/getInfo':{
    target: 'https://other-server.example.com',
    changeOrigin: true
  }
}

在 CREATE-REACT-APP 脚手架中,我们只需要在 package.json 中设置 porxy 代理属性,属性值是目标服务器的地址;在客户端发送请求的时候,请求的接口先保证是同源,如果当前源下没有这个接口,没关系,基于 dev-server 使用 webscoket 已经把目标代理服务器上的对应接口数据获取到了,所以直接请求同源下没有的接口,也可以获取数据!

方案四:ngnix 反向代理

方案五:node 作为中间件代理

===============

基于 IFRAME 实现跨域

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

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

  2. document.domain 只能处理主域相同,但是子域不同的情况 v.qq.coms.qq.com

  3. postMessage

沪ICP备20006251号-1