解决前端跨域的方式

175 阅读3分钟

前端跨域

1、概念

跨域影响:浏览器不能执行其他网站的脚本

  • Cookie、LocalStorage 和 IndexDB 无法读取
  • DOM 和 JS 对象无法获取
  • Ajax请求发送不出去

同源策略:浏览器对javascript添加的安全限制 同源策略是一种约定 是浏览器核心的安全功能

什么是同源:协议、域名、端口都相同

什么是跨域:不满足协议、域名、端口都相同

例如:以下链接是否与http://www.test_notice.com/index.html同源

http://www.test_notice.com/login.html同源

https://www.test_notice.com/index.html不同源(协议不同)

https://www.test_notice.com:80/index.html不同源(端口号不同)

https://www.test_not.com:80/index.html不同源(域名不同)

2、解决跨域

JSON和JSONP区别

JSON:(JavaScript Object Notation)一种轻量级的数据交互格式

JSONP:一种非正式传输协议,允许用户传递一个callback(或者一开始就定义一个回调方法)参数给服务端,然后服务端返回数据时会将这个callback 参数作为函数名来包裹住 JSON 数据,客户端就可以随意定制自己的函数来自动处理返回数据了。

大前提:web页面调用js文件不受跨域问题的影响,凡是拥有 src 这个属性的标签都拥有跨域的能力,比如img和script(就可以请求得到一个静态资源,本质上就是一个GET请求)

方式一:JSONP

和ajax没有关系,只支持 GET 请求 不支持post请求

核心:网页通过添加一个<script>标签,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。

原理:

  • 客户端利用 script 标签的 src 属性,去请求一个接口,因为 src 属性不受跨域影响(浏览器会把这一段字符串当做js来执行)
  • 服务端响应一个字符串
  • 客户端接收到字符串,然后把它当做 JS 代码运行

实现:

后端代码

app.get('api/jsonp',(req,res)={
    //接收客户端的函数名
    let fn = query.callback;
    let obj = {name:'圆圆',age:18}
    let str = JSON.stringify(obj)
	res.send(fn + `(${str})`)
})

前端代码(如果test.com域名下)

// 向服务器test.com发出请求,该请求查询字符串有一个callback参数,用来指定回调函数的名字
<script src="http://test.com/api/jsonp?callback=dosomething"></script>

// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
    	// 处理获得的数据
    	console.log(res.data)
}
</script>

缺陷:

安全问题(请求代码中可能存在安全隐患)

要确定jsonp请求是否失败并不容易

方式一:CORS

  • 前端什么也不用做
  • 后端只需要开启cors(跨域资源分享(Cross-Origin Resource Sharing))
  • 它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法
  • 使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败

方式三:proxy(跨域请求devServer代理中的几种配置)

No.1:只修改域名

接口请求的url格式形如:/myadress/aboutUs/info.php(而不是http://localhost:8081/myadress/aboutUs/info.php)

devServer:{
    proxy:{
        '/myadress':{
            target:'http://www.test_notice.com', // 要访问的跨域的域名
            ws:true, // 是否启用websockets
            changOrigin:true // 开启代理:本地会创建一个虚拟服务器,然后发送请求,并同时接收请求的数据,这样客户端和服务端进行数据交互就不会有跨域问题
        }
    }
}

实现:

No.2 :有标识

接口请求的url格式形如:/api/myadress/aboutUs/info.php

devServer:{
    proxy:{
        '/api':{
            target:'http://www.test_notice.com', // 要访问的跨域的域名
            ws:true,
            changOrigin:true,
            pathRewrite:{
                '^/api':''
            }
        }
    }
}

实现:

No.3:稍作省略

接口请求的url格式形如:/myadress/info.php

请求没写aboutUs,目的是跨域再加上

devServer:{
    proxy:{
        '/myadress':{
            target:'http://www.test_notice.com', // 要访问的跨域的域名
            ws:true,
            changOrigin:true,
            pathRewrite:{
                '^/myadress/':'/myadress/aboutUs'// 注意这里aboutUs后面没有/
            }
        }
    }
}

实现:

No.4:稍作省略(同No.3)

接口请求的url格式形如:/myadress/info.php

请求没写aboutUs,目的是跨域再加上

devServer:{
    proxy:{
        '/myadress':{
            target:'http://www.test_notice.com/myadress/aboutUs', // 要访问的跨域的域名
            ws:true,
            changOrigin:true,
            pathRewrite:{
                '^/myadress/':'/' //这里必须这样写
            }
        }
    }
}

实现