什么是跨域?
要了解跨域,先要说说同源策略。同源策略是由 Netscape 公司提出的一个著名的安全策略,所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当页面在执行一个脚本时会检查访问的资源是否同源,如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
跨域,指的是从一个域名去请求另外一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其他域名网站的脚本,是由浏览器的同源策略造成的,是浏览器施加的安全限制。跨域的严格一点来说就是只要协议,域名,端口有任何一个的不同,就被当作是跨域。
案例
有两个项目testA和testB,testA对外提供接口,testB提供页面调用testA的接口。
package com.example.demo.controller;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("server")
public class TestController {
@RequestMapping("test")
public Map<String, Object> test(HttpServletResponse httpResponse,HttpSession session){
System.out.println(session.getId());
Map<String, Object> map=new HashMap<String, Object>();
map.put("code",200);
map.put("data",null);
map.put("msg","成功");
return map;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
测试
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<div id="msg">
</div>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
url:'http://localhost:8090/server/test',
type:'get',
dataType:'json',
success:function(res){
console.log(res);
$("#msg").html(res.msg);
},
error:function(){
console.log("error");
}
})
});
</script>
</body>
</html>
在testB的页面中是用ajax调用了testA的接口
访问时会出现
进了error方法
由于两项目的端口不通,所以造成了跨域访问。
如何解决跨域问题?
其实解决跨域问题的方案很多,在此就介绍两种吧。
安装nginx代理服务器
配置文件中添加配置如下:
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://localhost:8091;
proxy_cookie_path / /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
location /server { #访问服务器路径
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass http://localhost:8090;
proxy_cookie_path /server /;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
就本次测试而言
将/ server开头的请求转发到http://localhost:8090服务,
其他都转发到http://localhost:8091服务
此时服务器对外只暴露一个ip所有请求都通过nginx代理。
修改请求路径
$(document).ready(function(){
$.ajax({
url:'/server/test',
type:'get',
dataType:'json',
success:function(res){
console.log(res);
$("#msg").html(res.msg);
},
error:function(){
console.log("error");
}
})
});
修改:url:'/server/test',
修改后访问成功
其中在服务器端(testA项目)添加配置
package com.example.demo.controller;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
在前端页面(testB项目)设置
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
url:'http://localhost:8090/server/test',
type:'get',
dataType:'json',
async:true,
xhrFields:{
ithCredentials:true
},
success:function(res){
console.log(res);
$("#msg").html(res.msg);
},
error:function(){
console.log("error");
}
})
});
</script>
其实就是加了
async:true,
xhrFields:{
withCredentials:true
},
添加了上述内容后访问成功
这样的话用session保存回话状态就会失效。
原因是两个项目都会产生一个sessionid,存在cookie中传输到客户端,如果一个新的cookie与一个已存在的cookie的NAME、Domain和Path属性值均相同,则旧的cookie会被丢弃。
所以就会产生发送到本服务器的sessionid永远是另一个服务器产生的sessionid,而不能被本项目所识别。就会造成一直产生新的sessionid。
跨域如何解决session冲突?
其实对于springboot项目来说,解决此问题很简单
只需要在其中一个项目中配置如图:
server:
port: 8090
servlet:
context-path: /
session:
timeout: 3600
cookie:
name: sessionid
只要保证name不同即可。
此时两服务器上的sessionid就会各自保持一致。