因为浏览器可以同时打开很多页面,可以同时保存很多授权信息,浏览器为了安全问题,采用了同源策略(浏览器存在跨域问题,服务器不存在跨域问题)
同源策略:是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
比如,浏览器的地址是baidu.com,页面通过ajax请求京东,就存在跨域,浏览器就阻止了该行为
现在有一个需求,两个服务器A和B,浏览器通过请求服务器A获取页面A,然后在页面A下通过ajax请求访问网页B,浏览器是不允许这样操作的,但是可以通过一些条件可以去实现
1.浏览器的页面A通过Ajax请求访问B页面时,浏览器可以先询问服务器B是否同意
如果页面A通过ajax直接访问页面B,会报错 cors -> cross origin resources sharing error,MissingAllowOriginHeader(跨域资源共享,丢失了允许跨域的头)
解决方案:
- @RestController
- public class UserController {
-
-
- //方式一:手动添加请求头
- @RequestMapping("/user")
- public User getUser(HttpServletResponse response){
- //第一个参数是添加一个请求头,第二个参数是允许请求的来源地址
- response.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8081");
-
- //10秒钟之内再次请求的时候,就不用发送预检请求了
- response.addHeader("Access-Control-Max-Age", "10");
-
- //允许你发送的请求是GET请求还是POST请求
- response.addHeader("Access-Control-Allow-Method", "GET");
-
- return new User("java", "java");
- }
-
-
- //方式二:添加注解@CROSSORIGIN
- @RequestMapping("/user")
- @CROSSORIGIN(origin = {"http://127.0.0.1:8081"})//添加来源地址
- public User getUser(HttpServletResponse response){
-
- return new User("java", "java");
- }
-
-
- }
浏览器的页面A访问页面B的时候,会发送两个请求,第一个请求是option——预检请求,第二请求是get——获取数据
2.服务器与服务器之间是不存在跨域问题的,因为浏览器可以同时打开十几个网站,这时,浏览器既有A页面的授权信息,也有B页面的授权信息,而服务器不可能打开十几个网站,并获取到别的页面的授权信息,否则A网站就相当于做了B网站的认证了,浏览器使得客户端能够将多个网站的用户信息都存在同一物理环境,而服务器只能保存自己所提供服务的信息
解决方案:浏览器通过网页A访问服务器A,服务器A再去访问服务器B,这样服务器A就相当于一个中间代理,去获取服务器B的网页信息
实现一:可以通过http请求服务器B获取网页B的数据,例如restTemplate,相当于手写一个方向代理服务器
实现二:nginx(方向代理,动静分离,负载均衡),修改配置文件
server {
listen 80;
server_name localhost;
##添加以下标红的部分
location /api {
proxy_pass http://127.0.0.1:8082; ##路径带有api的请求转发到端口为8082的服务器
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
正向代理:用户A访问Google,由于存在墙,用户A只能通过先访问香港的服务器,由香港的服务器转发请求到Google服务器,这种代理模式是,用户明确要访问的地址,由于无法直接访问到最终的服务器,只能通过中间服务器去访问,直接输入Google的地址就可以了
反向代理:用户B访问代理服务器,但是服务器B要访问哪获取数据,用户不知道
3.jsonp利用浏览器天然支持跨域的标签
后端代码
- @RequestMapping("/cross")
- public String cross(HttpServletResponse response){
- return "callback('123')"
- }
请求返回后,返回的字符串会调用前端方法cross,最终打印出123
当使用script请求地址时,会将返回的字符串,默认当成js解析。由于后端返回是的callback(xxx),所以会调用本地的callback函数。
从原理上来看,要使用JSONP,必须要后端返回相应的数据,这个就是JSONP的模式了,允许客户端传递一个callback函数,后端将数据包裹在callback函数中返回。
从原理也能看出,JSONP并不要求必须传递JSON格式的数据,只要是JS函数能够认可的数据都是可以传递的