51 解决vue前后端跨域问题
这里主要介绍借助vue脚手架解决ajax请求跨域的问题
说到ajax请求,就不得不说下xhr(XMLHttpRequest)了,它可以说是鼻祖,但是实际开发中,我们不会直接使用它,而是进行二次封装或者使用成熟的第三方封装,比如JQuery中的$.get,$.post都是由它进行封装的
51.1 axios介绍
既然说到封装了,那就不得不提到axios了,它和JQuery相比,它支持请求拦截器和响应拦截器,并且体积很小,大约是JQuery的四分之一体积,一般在vue项目里面,基本都是使用axios请求
本文将会使用axios进行请求
下载axios
想要使用axios,必须先下载它,打开终端,输入
npm i axios
这个库非常的小,安装很快
引入axios
下载完毕之后,就可以引用了
// 引入axios import axios from 'axios'
51.2 模拟场景
基本工作做完后,就可以开发前后端代码,模拟跨域场景了
后端接口
后端起一个服务,端口为9090,有一个get请求,先访问下,因为是get请求,可以直接在浏览器访问,所以说接口是没问题的
前端请求
有了后端的接口,我们就可以在前端去请求了,上述已经安装好了axios,所以直接编写代码请求后端接口,通过控制台可以看到,前端的端口是8080
<template> <div> <button @click="getInfo">获取信息</button> </div> </template> <script> // 引入axios import axios from 'axios' export default { name:'App', methods:{ getInfo(){ // 使用axios发送请求(get) 发送请求后会有两个回调 axios.get('http://localhost:9090/queryUserInfo').then( // 成功回调 success=>{ console.log('请求成功!') // 请求成功后的数据 console.log(success.data) }, // 失败回调 error=>{ console.log('请求失败!') // 请求失败原因 console.log(error.message) } ) } } } </script>
然后发送请求,发现控制台报错了,这是一个很经典的跨域问题
发现跨域问题
所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。
上面的例子就算因为前后端通信的端口不一致造成的跨域问题
常用的解决问题的手段有以下三种
1 cors
2 JSONP
3 代理
我们一一举例说明
51.3 解决跨域
cors
这种方式是我工作中处理跨域用到最多也是最简单的一种方式,直接通过注解解决跨域问题
cors解决跨域,一般不用于前端做任何事,而是后端或者服务器去操作,其实就是在服务器里面返回相应的时候加几个响应头,某种程度上来说,cors解决跨域才是真正意义上的解决跨域,但是在开发中,这个响应头不是随便配置的,如果随意配置,就会造成一个问题就算任何人都能找服务器要数据,存在一些安全风险
注解解决跨域
在后端的controller或某个具体方法上可以加上@CrossOrigin注解解决跨域
加完注解后,这个时候重启后端服务器再访问,发现问题解决
值得注意的是,@CrossOrigin这个注解默认是解决全部路径的跨域,有时候一些参数需要自己设置,否则可能会有安全隐患
全局配置跨域
如果使用注解,那么我们需要在每一个controller或者方法上都要加上注解才能解决跨域的问题
那么有没有一种一劳永逸的办法呢?
当然有,我们可以使用全局配置跨域,代码如下:
注意:一定不要忘了使用@Configuration注解配置到项目中,否则无效,具体的一些参数或者路径,根据自身需求设置即可
package com.wyh.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsMapping implements WebMvcConfigurer { @Override /** * 重新跨域支持方法 * CorsRegistry 开启跨域注册 */ public void addCorsMappings(CorsRegistry registry) { //addMapping 添加可跨域的请求地址 registry.addMapping("/**") //设置跨域 域名权限 规定由某一个指定的域名+端口能访问跨域项目 .allowedOrigins("*") //是否开启cookie跨域 .allowCredentials(false) //规定能够跨域访问的方法类型 .allowedMethods("GET","POST","DELETE","PUT","OPTIONS") //添加验证头信息 token //.allowedHeaders() //预检请求存活时间 在此期间不再次发送预检请求 .maxAge(3600); } }
以上就是通过cors解决跨域的两种方式
JSONP
除了使用cors解决跨域,还可以使用JSONP,它解决跨域的方式其实挺巧妙的,它借助了script标签li的src属性,在引入外部资源的时候不受同源策略限制的特点办到的,虽然JSONP比较巧妙,但是真正开发中用到的微乎其微,因为想要实现JSONP解决跨域,不仅仅要前端人员要用到特殊写法,后端人员也得配置前端才能实现,并且只能解决get请求跨域问题,相对来说很鸡肋
这里就得吐槽一句了,虽然开发用的少,但是面试就喜欢问你JSONP,就看你知道不知道这个巧
代理
除了cros和jsonp,还有一种代理方式,这种用的相对来说也很多, 一般代理服务器
这个概念很好理解,相当于生活中的中介
在前后端直接配置一个代理服务器,这个代理服务器和前端处于一个位置,当前端向后端请求数据的时候,不会直接访问后端,而是找这台代理,代理收到前端的请求,转发给后端,如果收到后端的响应数据,就把这些数据返回给前端
代理服务器的方式有一个东西大家应该都听说过:nginx,但是nginx一般属于后端人员掌握的,这里使用一种对前端人员更加友好的技术:cli,没错,就是vue的脚手架,它就可以帮助我们代理服务器,相比nginx它简单的不能再简单了,只需要短短几行代码就可以搞定
注意:vue-cli给我们提供了两种配置代理服务器的方式,各有千秋,使用的时候只能二选一,不能同时使用
vue脚手架配置方式1
既然想对脚手架进行配置,肯定要改一个文件,就是vue的配置文件:vue.config.js,肯定要在这里面写代码,然后代理服务器就开起来了,到底怎么写,可以参考官方文档:https://cli.vuejs.org/zh/config/#devserver-proxy
复制配置代码进行修改配置文件
注意:这里的端口是要请求后端的端口,并且只需要写到端口即可,我的后端端口是9090
// 开启代理服务器 devServer: { // 代理的端口是要请求后端的端口 写到具体的端口即可 不需要写具体的路径 proxy: 'http://localhost:9090' }
注意:这种代理简单,但是不完美,原因在下面
这样就配置了一个代理服务器,一定要重启脚手架
重启完成后再次访问,还是报错跨域问题!
注意:虽然已经配置了代理服务器,但是还没用到这个代理,所以请求的时候不应该是后端的端口9090,而是代理的端口8080,这里就要写全路径了,不能和配置代理服务器的时候一样只写端口了
再次访问,发现正常了,说明代理有效
这种代理有两个误区(坑),下面一一说明
两个误区(坑)
误区1
不能灵活的控制到底走不走代理
首先,这种代理不是什么都会代理给后端的,如果代理的东西前端有,就会直接返回,就不去找后端,比如下面这个例子
我在public目录写一个叫queryUserInfo的文件,没错,和后端的接口名称一样
这时候请求就会发现,找到前端的内容就不会访问后端了
误区2
这种代理只能代理一个服务器不能代理多个服务器,也就是说目前代理的8080只能把请求交给9090,不能转发给别人了
vue脚手架配置方式2
上面的代理方式,虽然简单,但是也有两个坑,不够完美,想要追求完美,还得是这种方式
那么这种方式怎么写呢?还是继续看官方文档:https://cli.vuejs.org/zh/config/#devserver-proxy
注意:这种配置代理和上面的配置代理只能二选一,不能同时使用!
把代码复制到配置文件,进行修改
devServer: {proxy: {'/api': {target: '<url>',ws: true,changeOrigin: true},'/foo': {target: '<other_url>'}}}
这里面有一些属性,有的属性可以配置使用,我们一一说明
注意:不管修改哪个属性,都要重启vue!
/api和target
/api指的是请求前缀 这里的api可以更改 不一定非要叫api
target指的是如果请求前缀匹配上了,那么就找代理服务器请求
比如现在我请求的路径不变还是上面的路径
那么还是一样的效果
这时候我把api前缀加上,理论来说可以了,但是还是不行
不过这次不是跨域的问题了,只是找不到请求
找不到请求是对的,因为的后端请求没有/api的前缀,那么如果忽略这个前缀呢?
pathRewrite
有这么一个属性,官方没有说:pathRewrite
// 忽略前缀路径 它是一个对象 里面是key value // 这个正则意思是 如果前缀是/api,那么会替换成空字符 pathRewrite:{'^/api':''}
这个时候再测试,发现正常
ws
ws是websocket的缩写,用于支持websocket,默认为true,本人对websocket不是很了解,所以不多叙述!
changeOrigin
用于控制请求头中的host值
或者说是否真实汇报自身情况 true不真实 false真实 一般为true,默认也是true
为什么这么说呢?我们通过下面案例查看,这时候我后端获取请求的主机信息,大家注意观察
改为false,好家伙,你小子反水是吧
配置多个代理
如果想要配置多个代理,直接复制一个即可,注意加上逗号,修改端口和前缀
我这里目前有一个服务器,就不演示了,不想再开个服务了QAQ
vue脚手架配置代理总结
vue脚手架配置代理
方法一
在vue.config.js中添加如下配置:
devServer:{ proxy:"http://localhost:5000" }
说明:
- 优点:配置简单,请求资源时直接发给前端(8080)即可。
- 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。
- 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)
方法二
编写vue.config.js配置具体代理规则:
module.exports = { devServer: { proxy: { '/api1': {// 匹配所有以 '/api1'开头的请求路径 target: 'http://localhost:5000',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api1': ''} }, '/api2': {// 匹配所有以 '/api2'开头的请求路径 target: 'http://localhost:5001',// 代理目标的基础路径 changeOrigin: true, pathRewrite: {'^/api2': ''} } } } } /* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080 changeOrigin默认值为true */
说明:
- 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
- 缺点:配置略微繁琐,请求资源时必须加前缀。