什么是跨域、怎么解决跨域以及如何实现跨域下的登录

在实际项目中,前后端分成两个不同的项目,各自部署在不同的域名下,这就遇到跨域问题了

1、什么是跨域

在浏览器同源策略限制下,向不同源(不同协议、不同域名或者不同端口)发送XHR请求,浏览器认为该请求不受信任,禁止请求,具体表现为请求后不正常响应

从定义中可以看到这都是浏览器做的“好事”。那么什么是不用源呢?其实也很简单,只要页面的协议、域名和端口与请求地址的没有完全一样,就认为你是不同源,举个极端例子来说:

http://www.baidu.com:80

https://msg.baidu.com:8080

2、怎么解决跨域

只要思想不滑坡,办法总比困难多,既然已经了解什么是跨域,那我们就着手来解决这个问题

1.从浏览器入手

其实跨域只在浏览器下才会触发,那有没有办法禁用浏览器的同源策略呢?办法还真的有。

对于IE浏览器:进入ie的网际网路选项设置,然后选择安全性,再选择自订等级,然后下拉,找到「存取跨网络的资料来源」,选择启用即可;

对于chrome浏览器:通过在命令行,输入chrome.exe --allow-file-access-from-files --user-data-dir=“C:/Chrome dev session” --disable-web-security,这会新建一个浏览器实例,自动打开的chrome会显示一系列黄色的文字就说明成功了;

对于FireFox浏览器:在地址栏输入about:config,然后下拉找到security.fileuri.strict_origin_policy,然后设置为false即可

2.从域名入手

既然域名等信息不一致导致跨域产生,那么干脆就把两个项目合并成一个项目,使用相同的协议、域名和端口。

3.从jsonp入手

其实认真想想,我们的系统中经常会用到外链的图片、样式文件以及插件,那这些不会导致跨域吗?是的,真的不会,因为这些是http请求,并不是前面定义的xhr(XmlHttpRequest)请求。

既然图片和js脚本可以正常请求,那么如果把script脚本的src改成我需要跨域请求的url是不是就可以了呢?

是可以的,当请求接口返回的数据需要稍微处理下。在平常引入script脚本时,下载完文件后自动执行,如果我们把src改成跨域url,而且返回值是一段jjs语句,比如:

req.send(“alert(1)”); //后台返回js语句

那么前台会会自动解析并执行(这里是弹出1)。那么,如果返回的js语句是一个调用函数的js语句,恰巧前台事先定义了该函数,如:

//前台

function fun(msg){ alert(msg); }

//后台

req.send(“fun(‘你渴望力量吗’)”);

那么在fun函数将被调用(可以理解成后台调用前台代码),如果对fun的参数进行处理,就可以实现复杂的业务逻辑了。

在实际情况下是怎么处理的呢?一般我们会先协商好需要被调用的方法及参数(fun),然后动态创建一个script标签,并设置该标签的src为跨域url,最后插入到文档中,插入后,浏览器会自动发起http的get请求,下载完成后将会执行后台返回的js语句(后台调用前台)。

这就是jsonp。

4.从代理入手

还是回到最开始,既然浏览器认为非同源不安全,那么向同源请求不就行了?我们把请求转到同一项目下的后台,在同项目的后台进行xhr请求,然后把请求结果原样返回给前台,这就是代理(或者叫转发)。

成功的原因是同源策略只在浏览器下才起作用,我用后台来请求其他的url,那是不受影响的。开启后台代理可以用C#、JAVA、NodeJs、甚至是python都行,只要能被前端访问的并且能转发请求就可以。

5.从CORS入手
除了前面的几种方法外,还有一种简单得多的方法,那就是后台的请求响应头告诉浏览器“我的这个请求很安全,允许当前域名跨域访问”。如何去实现的呢,其实这是利用了CORS(Cross-Origin Resource Sharing, 跨源资源共享),听起来牛逼哄哄的,其实也就是一个W3C新标准,浏览器检测到响应头的一些字段的值后,跳过同源策略。

那么有那些响应头字段,以及它们分别是什么定义呢?

res.header(“Access-Control-Allow-Origin”, “*”); //允许全部域名跨域,可以指定特点域名,逗号分隔

res.header(“Access-Control-Allow-Credentials”, “true”); //允许携带cookie

res.header(“Access-Control-Allow-Headers”, “X-Requested-With”); //允许传输的请求头

res.header(“Access-Control-Allow-Methods”, “PUT,POST,GET,DELETE,OPTIONS”); //允许发送的xhr模式

res.header(“X-Powered-By”, " 3.2.1"); //快速模式

res.header(“Content-Type”, “application/json;charset=utf-8”); //类型及字符编码

3、如何实现跨域下的登陆

用前面任意一种方案都可以解决跨域,然而,跨域带来的登陆问题却不好解决。在说如何解决登陆问题前,还是按照老规则说一下问什么就登陆不了了。

在解析前需要先明确几点:

1:http是无状态的,不知道该请求归属于谁
2:每次http请求都会自动携带cookie(在请求头中)
3:session存放在服务端,是有时间有效性的,一段时间内不访问将失效

在正常情况下(非跨域),我们前台发出post请求,携带账号、密码、验证码,提交给后台,后台检查数据后,设置session并返回登陆信息完成登陆,这就是一个简单的登录流程。当用户发起一个新的请求的时候,后台通过请求上下文可以获取到已经保存在服务端的session信息,如:

req.session[“UserInfo”]
//登录时设置了key为UserInfo的session
乍一看就是这么一回事,当时仔细想想又会发现奇怪的地方:

①都说了http是无状态的,在上一个请求设置的session,为什么在下一个请求中可以获取到呢?

②session的key是UserInfo,如果有多个用户同时操作,拿到的值会不会是同一个呢?

接下来我们先介绍一下session的设置与读取

说起session,就不得不说cookie,两者都是缓存,只不过前者保存在服务端,后者保存在客户端。在登录完成后,后台设置一个key为UserInfo的session对象(就叫对象S吧),这个对象S有三个重要的属性,分别是key、value以及sid。key和value的非常好理解,那sid是拿来干嘛?

其实sid又叫session_id,是这个session对象的主键。

众所周知,http是无状态的,为了区分状态,在设置session的时候,服务端会自动在http请求的响应头中把sid设置到cookie中(开发人员感知不到这步操作的,也就是自动设置cookie),浏览器响应请求后,会把更新带有sid的cookie,并在下一个请求时自动带上cookie(浏览器请求自动携带cookie,也是静默操作,关于携带cookie的后面还会继续介绍)。

当第二次请求来到后台,此时已经带上了sid的cookie,如果这时候获取session,服务器将会遍历session列表,匹配所有sid是cookies中的sid的session,再通过key作为索引找到相应的结果。

发布了33 篇原创文章 · 获赞 12 · 访问量 899

猜你喜欢

转载自blog.csdn.net/weixin_45630042/article/details/103743497