这周接了一个会议管理系统那里练手,也是自己负责的第一个项目,从需求分析,数据库的设计,到开始动手搭框架些项目,都是都对前面学习的一次整合。
后台在开发接口时,使用postman测试时,接口都可以正常完成功能,所以就放到了服务器上给前端测试。在测试时问题就出来了;
后台:ssm+shiro框架
前端:vue.js
问题描述:
该项目的登录先由后台生成一验证码返回给前端,并保存在session中,不过当前端登录时,后台会报 NullPointerException,看前端的请求头才发现前端的请求中并没有携带cookie信息,而且会发生几次请求;
开始我们以为这就是经典的跨域问题,然后我就去了解了跨域
什么是跨域
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
域名:
- 主域名不同: http://www.baidu.com/index.html –>http://www.sina.com/test.js
- 子域名不同: http://www.666.baidu.com/index.html –>http://www.555.baidu.com/test.js
- 域名和域名ip: http://www.baidu.com/index.html –>http://180.149.132.47/test.js
- 端口:http://www.baidu.com:8080/index.http->http://www.baidu.com:8081/test.js
- 协议:http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
1. 端口和协议的不同,只能通过后台来解决
2. localhost和127.0.0.1虽然都指向本机,但也属于跨域
为什么会有跨域
因为浏览器的同源策略:
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
不管怎么样,我们都是需要同源策略的,那么如何解决跨域了,前后端都有自己的解决方案,
解决跨域
前后端都有自己的解决方案,前端有jsonp专门用于解决跨域,不管只能使用get请求,很不方便;所以后端解决跨域会方便一些
CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。看名字就知道这是处理跨域问题的标准做法。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否
Access-Control-Allow-Origin:指定授权访问的域Access-Control-Allow-Methods:授权请求的方法(GET, POST, PUT, DELETE,OPTIONS等)复制代码
在后台我通过spring mvc的拦截器去实现:
在spring-mvc-xml配置自定义拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.cqupt.meeting.interceptor.ResponseInterceptor" />
</mvc:interceptor></mvc:interceptors>复制代码
后台配置完成后,问题仍然没有解决,我再次查看请求,发现每次请求都会有Options方式的请求,下面我们看看这个options请求是怎么来的
CORS有两种请求,简单请求和非简单请求:
(1) 同时满足以下两大条件,就属于简单请求:
- 请求方法满足一下之一
2. get
3. post
- HTTP的头信息不超出以下几种字段:
1. Accept
2. Accept-Language
3. Content-Language
4. Last-Event-ID
5. Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
(2)非简单请求
非简单请求会发出一次预检测请求,返回码是204,预检测通过才会真正发出请求,这才返回200。
在 CORS 中,可以使用 OPTIONS 方法发起一个预检请求,以检测实际请求是否可以被服务器所接受。预检请求报文中的Access-Control-Request-Method
首部字段告知服务器实际请求所使用的 HTTP 方法;Access-Control-Request-Headers
首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
他的作用是用于试探服务器的响应是否正确,即是否能接受真正的请求,如果在options请求之后获取到的响应是拒绝性质的,例如500等http状态,那么它就会停止第二次的真正请求的访问,应对这种跨域预检机制,后台可以通过设置Access-Control-Max-Age来控制浏览器在多长时间内(单位s)无需在请求时发送预检请求。
但是到这,前端的session还是没有发送过来,这时我觉得这可能不是跨域了,应该是前端配置问题,然后百度后知道,使用axios请求时默认并不会带上web浏览器的cookie,需要进行以下的设置:
// 网络请求框架
import axios from 'axios'
axios.defaults.withCredentials=true //让ajax携带cookie
Vue.prototype.$http = axios // 这样设置就可以在组件内用 this.$http 使用axios了
axios.defaults.baseURL = '' //初始化基础地址复制代码
加上后,终于把session传给后台了,完成了登录;
总结:
在与前端及交互过程中,问题肯定是很多的,就比如这个跨域问题,都认为是对方的的问题,但是在一步步的解决过程中,问题其实是双方的,所以在交互时,面对问题不能相互甩锅,而是要学会质疑,不但要质疑别人,更重要的是质疑自己。