跨域问题详解
Posted 小小本科生
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跨域问题详解相关的知识,希望对你有一定的参考价值。
一、跨域原理
1.为什么会产生跨域问题
之所以会产生跨域问题是由于浏览器实现了同源策略(Same origin policy),同源策略规定发起ajax请求时当原地址(原始域)和请求地址(请求域)的协议、域名、端口号三者任意一个不同就会引起跨域问题。
2.什么是同源策略
百度百科:同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
3.思考
也就是说跨域只会在浏览器端或者实现了同源策略的其他地方发生,这为跨域问题的解决提供了思路,也从侧面解释了为什么android开发时直接请求服务器数据不会产生跨域问题,而在前后端分离的项目中会跨域。那么,问题来了。当我访问百度页面的时候,我的域名是localhost(127.0.0.1),或者映射到互联网上映射成了另一个ip,但总归不能和百度的ip相同吧,为什么不会产生跨域呢?因为浏览器的地址栏不存在跨域问题,只有发送ajax请求时才可能产生跨域。what?你在说什么?你是让我记住这句话吗?这是规定吗?什么破文章!不,不,不,你听我解释,我们所说的原始域是指ajax文件存在的位置,如果直接在地址栏输入http://www.baidu.com,那么你的原始域就是www.baidu.com,何来跨域一说。
4.跨域会有什么后果(现象)
如果跨域了,也就是如果不满足浏览器实现的同源协议,则会产生以下后果:
(1)无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
(2)无法接触非同源网页的 DOM
(3)无法向非同源地址发送 AJAX 请求
二、为什么跨域时两次请求的sessionId不一致
这就要从前后端交互的原理讲起了。http请求是无状态的,也就是说当我第一次访问服务器登录后,再发送下一个查看个人信息的请求,服务器并不知道我之前已经登录过了(因为http协议是无状态的),所以还是认为你没有登录,这就衍生出了session和cookie。关于session和cookie的介绍可以参考https://www.jianshu.com/p/58d66eb287e5
(1)浏览器发送登录请求,第一次请求时服务器会生成一个session,可以将用户的一些信息存储到session中。
(2)当请求返回时服务端调用Set-Cookie将sessionId存到cookie中并返回给浏览器存储。
(3)浏览器带着cookie请求个人信息的接口,服务器从cookie中取得sessionId,并根据这个id找到对应的session,查看此用户 的信息是否和之前存储的一致。
(4)服务器返回个人信息数据并将cookie也返回便于浏览器下次请求时带着。
如果跨域了就是另一种状态了
(1)浏览器发送登录请求,第一次请求时服务器会生成一个session,可以将用户的一些信息存储到session中。
(2)当请求返回时服务端调用Set-Cookie将sessionId存到cookie中并返回给浏览器存储。但是由于跨域问题浏览器并不存储这个cookie
(3)浏览器请求个人信息的接口,但是带不上cookie。服务器生成一个新的session,从session中找不到用户信息,此时又生成了一个新的session,那么两次请求的sessionId必然不一致
(4)服务器告诉浏览器我找不到你的登录信息,浏览器端显示为两次请求的sessionId不一致,且明明登录了了服务端仍旧显示 未登录。
三、如何解决跨域问题
思路:1.前端、后端、浏览器都允许跨域
2.前端、后端都允许带有cookie
后端:
自定义一个过滤器,为HttpServletResponse允许跨域且允许携带cookie
private void crossDomain(HttpServletRequest request, HttpServletResponse response, String url)
response.setCharacterEncoding("UTF-8");
log.info("REFERER:", request.getHeader("REFERER"));
//允许来自所有域的访问
response.setHeader("Access-Control-Allow-Origin", "*");
//允许客户端携带验证信息,例如 cookie 之类的
response.setHeader("Access-Control-Allow-Credentials","true");
//响应标头指定响应访问所述资源到时允许的一种或多种方法预检请求。
response.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
//允许浏览器header中带有哪些字段
response.setHeader("Access-Control-Allow-Headers",
"Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,Authorization");
前端:允许跨域且在跨域时强行携带cookie
export const axiosInstance = axios.create(
baseURL: baseURL,
timeout: 100000,
headers:
common: (() =>
if (window.localStorage)
// const jwt = window.localStorage.getItem('jwt')
// 从sessionStorage中读取token信息
const jwt = sessionStorage.getItem('jwt')
return 'Authorization': `Bearer $jwt`
else
return
)()
,
xhrFields:
// 强行携带cookie
withCredentials: true
// crossDomain: true
)
目前按道理说是应该解决跨域问题了,但是必须将后端的
response.setHeader("Access-Control-Allow-Origin", "*");
这行代码中的*改为浏览器具体ip,不能用*
这样的话一对一调试没问题,但如果前端也是多人开发的话调试依然不方便。此时我们要将浏览器也设为允许跨域才行
四、设置浏览器允许跨域
1.随便建立一个文件夹,比如我在地盘建了一个myChromeData
2.赋值一个chrome的快捷方式
注意:一定不要在原快捷方式上操作,因为使用设置了允许跨域后的浏览器浏览网页时将受不到同源策略的保护,你访问的带有恶意代码的页面可以直接获取甚至操作你同时访问的带有你敏感信息(比如银行、微博)。所以这个快捷方式设置好之后只用来开发测试就好了。
右键chrome快捷方式->属性->目标,在原目标后面加上 --disable-web-security --user-data-dir=D:\\myChromeData
注意最前边有个空格
打开浏览器显示您使用的不是受支持的命令行标记: --disable-web-security则说明设置成功了。有时候浏览器会自动恢复默认设置,只需要再重新设置一次就可以了。
好了,终于可以愉快的开发了。
以上是关于跨域问题详解的主要内容,如果未能解决你的问题,请参考以下文章
护照Facebook登录中的“对于需要预检的跨域请求是不允许的”错误?
该请求被重定向到“https://..com/site/login?”,这对于需要预检的跨域请求是不允许的
我正在使用 angularjs 和 django-cors-headers 然后给出“这对于需要预检的跨域请求是不允许的。”