近期在做一个商城时,采用前后端分离开发,前端用vue,后台用SpringCloud微服务。业务流程为,商城前端通过跨域请求微服务网关(Zuul集群),由网关路由到各个微服务节点。
    遇到的问题:1.请求跨域,2.Session 需要共享,问题大家都知道,不多讲,直接上解决办法。

    解决办法:

一.前端:

前端都采用POST方法请求后台,在main.js中增加一个拦截器

Vue.http.options.emulateJSON = false;
// Vue.http.options.emulateJSON = true;
Vue.http.options.xhr = { withCredentials: true };
Vue.http.interceptors.push((request, next) => {
  request.credentials = true
  next()
});
目的是拦截每一个post请求,设置withCredentials: true属性,以便客户端请求强行上送Cookie信息。

二.后台网关

1.跨域问题

在Zuul网关创建一个post类型的过滤器,增加以下代码:
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();

String origin = request.getHeader("Origin");
        if(origin == null) {
            origin = request.getHeader("Referer");
        }
        context.addZuulResponseHeader("Content-Type","application/x-www-form-urlencoded");
        context.addZuulResponseHeader("Access-Control-Allow-Origin",origin);
        context.addZuulResponseHeader("Access-Control-Allow-Credentials","true");

2.Seesion管理
微服务Seesion管理采用HttpSession。
(1)pom.xml 增加依赖
<!-- spring session -->
		<dependency>
			<groupId>org.springframework.session</groupId>
			<artifactId>spring-session</artifactId>
		</dependency>
		<!-- redis -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-redis</artifactId>
			<version>1.4.7.RELEASE</version>
		</dependency>

(2)增加HttpSession全局配置:
@EnableRedisHttpSession
public class HttpSessionConfig {
    @Bean
    public JedisConnectionFactory connectionFactory() {
        JedisConnectionFactory connection = new JedisConnectionFactory();
        connection.setHostName("192.168.10.10");
        connection.setPort(6379);
        return connection;
    }
}

(3)应用:在Zuul pre类型的过滤器中校验用户登录状态
 RequestContext context = RequestContext.getCurrentContext();
 HttpSession session = request.getSession();
 UserInfo userInfo = (UserInfo) session.getAttribute("userInfo");
 if(userInfo==null){
	 // 需要校验登录状态
	context.setSendZuulResponse(false);
	context.setResponseStatusCode(200);
	Iresp_common iresp_common = new Iresp_common("2000","尚未登录");
	context.setResponseBody(gson.toJson(iresp_common));
	return null;
}

以上 解决方案只针对安卓浏览器,和PC电脑浏览器。由于苹果手机版safari和MAC版Safari默认是阻止向第三方网站请求Cookie信息的,所以程序层面的跨域解决方案无法绕过IOS系统浏览器。如需兼容IOS系统,本人想到的办法是用nginx做代理,人为使前后端处于同一IP,端口环境下,骗过浏览器,这样就不存在跨域问题了。具体办法如下:

通过nginx进行路由配置,凡是 http://192.168.10.10:10022/userinfo/**类型的请求全部转发至http://192.168.10.221:9980/ (Zuul集群网关),以此类推完成如下配置(因目前微服务拆分了四个服务,所以只需配置四条信息)
http://192.168.10.10:10022/userinfo/**  ==> http://192.168.10.221:9980/ (Zuul集群网关)
http://192.168.10.10:10022/order/**  ==> http://192.168.10.221:9980/
http://192.168.10.10:10022/product/**  ==> http://192.168.10.221:9980/
http://192.168.10.10:10022/pay/**  ==> http://192.168.10.221:9980/

http://192.168.10.10:10022/开头的其他请求都转发至http://192.168.10.10:10020/(前端商城)
以上配置完成,即可实现同源访问。商城地址为:http://192.168.10.10:10020/ 后台网关的IP和端口也为http://192.168.10.10:10020/

第二种方案能彻底解决跨域问题,但是开发阶段,不适合本地调试,所以建议两种方案结合使用,这样既支持本地PC调试,也可保证生产环境全面支持安卓和IOS系统。


 






Logo

前往低代码交流专区

更多推荐