springboot跨域问题及其解决方案

weblog 精帖
460

什么是跨域?

要了解跨域,先要说说同源策略。同源策略是由 Netscape 公司提出的一个著名的安全策略,所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当页面在执行一个脚本时会检查访问的资源是否同源,如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。

那么什么是跨域呢?

跨域,指的是从一个域名去请求另外一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其他域名网站的脚本,是由浏览器的同源策略造成的,是浏览器施加的安全限制。跨域的严格一点来说就是只要协议,域名,端口有任何一个的不同,就被当作是跨域。

案例

有两个项目testA和testB,testA对外提供接口,testB提供页面调用testA的接口。

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;
	}
}
testB项目页面 

 

<!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方法   

由于两项目的端口不通,所以造成了跨域访问                    

如何解决跨域问题?

其实解决跨域问题的方案很多,在此就介绍两种吧。

1.nginx代理

安装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',
修改后访问成功

跨域资源共享(CORS)

 其中在服务器端(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
	},

添加了上述内容后访问成功

ss

但是上述两种方式虽然都解决了跨域问题,但是session却产生了冲突

这样的话用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就会各自保持一致。

猜你喜欢