1. 背景
近期参与了公司一个项目的重构设计工作,该项目系统由java语言和C++语言编写而成,是一个B/S架构的系统。在部署上主要使用单服务器部署。Web服务端文件部署在tomcat服务器上,不同功能模块使用不同的web目录隔开。系统的页面主要使用JSP编写,前后端代码耦合在一起,使用的第三方框架比较多,如在MVC框架上,就使用了struts2和spring mvc两种框架。
为了方便团队对于前后端分别开发与调试及向分布式服务系统的转换,有必要重构现有系统向前后端分离与分布式服务化转换。
2. 目标
我们重构的理想目标是实现微服务体系的改造,并最终可以不同服务部署于公司统一容器管理平台实现系统的可伸缩性。
由于使用了JSP技术,原有的系统前后端耦合比较紧密,因此我们首先把前后端分离的目的放在首位。
3. 前后端分离的方案
3.1 由本域转发的方案
计划使用spring boot框架,基于zuul组件构建一个API 网关,该网关同时又是一个前端服务器,放置系统的所有前端静态页面。所有对于后端服务的rest API请求都经过zuul网关转发到对应的服务。系统结构如下图所示(其实还存在很多问题,如服务间共享session等问题待以后逐步改造):
本域转发方案
网关使用spring boot框架和zuul组件构建,在网关的配置文件中可按如下规则配置:
#配置dmu的路由示例
zuul.routes.dmu.path=/dmu/**
zuul.routes.dmu.stripPrefix=false
zuul.routes.dmu.url=http://IP_DMU/ #这里配置dmu服务的访问地址
#zuul的全局配置
#保证头中的"Cookie", "Set-Cookie", "Authorization"不被过滤
zuul.sensitive-headers=
#保证返回的结果中重定向的主机是zuul主机,而不是下级被转发的机器,在Camden版本之后支持
zuul.add-host-header=true
对于网关的请求根据不同服务的路由规则(由URL的前缀来区分)转到不同的服务。
3.2 前端跨域的方案
这种方案中前端服务器不再将前端的请求转发到后端的各服务,而是直接通过浏览器实现ajax的跨域请求。
前端代码(使用Jquery)Ajax的POST请求如下示例:
$.ajax({
type: "POST",
url: "http://IP2/cas/login",
contentType: "application/json;charset=utf-8",
headers: {
},
data: JSON.stringify(
{
username: username,
password: password
}),
dataType: "json",
crossDomain: true, //POST跨域必加
success: loginResult,
error: ajaxError
});
服务端如果使用spring boot框架作为服务,需要支持跨域请求,方法是在原服务中增加如下类:
@Configuration
@EnableAsync
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*").allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600).allowCredentials(true);
}
}
这种方案实际是应用了W3C提交的跨源资源共享(CROS)方案,在运行本文的示例时,会发现浏览器将该跨域请求视为非简单请求,先向后端发了一个option请求,确认服务器端允许跨域后,再提交post提交。
4 小结
两种前后端分离的方案,我更倾向于基于本域转发的方案,因为这样在可控制性方面更好。当然不管哪种方案,都需要解决路由地址的配置问题,可以在运行前在文件中配置好,也可在运行初始化时从中心配置服务器获取(网上已有支持zuul动态加载路由信息的方法)。
网友评论