在 《服务注册、发现和远程调用》 这篇文章中介绍关于服务注册、发现和远程调用的一个 Demo,本文在这篇文章的基础上介绍如何使用 Spring Cloud Gateway 搭建一个网关。
一、问题
在上篇文章中,分别创建了 service_user 和 service_dict 两个服务,两个服务分别使用了 8001 和 8002 两个端口。这样直接通过 PostMan 或浏览器调用其中的接口没什么问题,如下图所示。
从上图可以看到,访问 user 使用了 8001 端口,访问 dict 使用了 8002 端口,如果要为这些服务提供一个页面,由于不同的服务使用了不同的端口号,那么在写前端页面时就会因为有多个端口而导致难以管理,使得开发变得复杂。为了解决该问题,那么此时,我们可以通过反向代理来进行完成,比如 Nginx。
二、使用 Nginx 的反向代理功能来完成请求的分发
在上面抛出的问题中,我们可用使用 Nginx 的反向代理功能来进行解决,解决的方法也很容易。这里 Nginx 直接下载一个 Windows 版本的进行测试。对 Nginx 进行简单的配置,配置如下:
server { listen 9001; server_name localhost; location ~ /user/ { proxy_pass http://localhost:8001; } location ~ /dict/ { proxy_pass http://localhost:8002; } }
这里通过配置了两个 location 完成了服务的分发,并且可用使用统一的端口 9001,测试如下图所示。
可用看到,通过访问 localhost 的 9001 端口可用正常的访问 service_user 和 service_dict 两个服务。接着,我们写一个页面,通过页面来调用 localhost 的 9001 来访问这两个服务。
三、编写简单的页面进行测试
这里使用 vue-admin-template 来进行测试,我们直接在登录页进行测试,然后通过 F12 的调试窗口来进行观察。先添加接口调用的代码,代码如下:
export function getUser() { return request({ url: 'http://localhost:9001/admin/user/getUser/1', method: 'get' }) }
然后再登录页面中进行调用,调用的代码如下:
getUsers() { getUser().then(response => { console.log(response) }).catch(error => { console.log(error) }) },
最后我们让页面打开时就进行调用,代码如下:
created() { this.getUsers() },
然后我们来观察调用的请求,如下图所示。
从两幅图中可用看出,接口并没有调用成功,因为发生了跨域的问题。我们可以在每个控制器上增加 @CrossOrigin 注解,也可以给每个服务添加一个配置类。同样,我们可以在两个服务前面增加一个网关,让网关来做路由分发和处理跨域的问题。
四、使用 Spring Cloud Gateway 网关
网关的作用比较多,网关可以做鉴权、限流、日志等功能,这里只是使用它做一个路由分发和处理跨域的问题。
在项目中创建一个子模块,命名为 gateway,接着来引入它的依赖,依赖如下:
<dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>2.2.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> <version>2.2.0.RELEASE</version> </dependency> </dependencies>
第一个依赖是做 Nacos 服务发现的,第二个就是网关的依赖。
引入依赖之后,创建 config 包,然后写一个用于允许跨域的 Bean,代码如下:
@Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*"); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }
有了上面的代码就可以让前端完成跨域请求,这里需要注意,在网关有了上面的跨域配置,那么在实际服务的 Controller 类上面就不可用再使用 @CrossOrigin 注解了,否则会报错。
创建一个 application.properties 文件,然后来配置路由分发,配置如下:
# 服务端口 server.port=7000 # 服务名 spring.application.name=service-gateway # nacos服务地址 spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848 #使用服务发现路由 spring.cloud.gateway.discovery.locator.enabled=true #设置路由id spring.cloud.gateway.routes[0].id=service-user #设置路由的uri spring.cloud.gateway.routes[0].uri=lb://service-user #设置路由断言,代理servicerId为auth-service的/auth/路径 spring.cloud.gateway.routes[0].predicates= Path=/*/user/** #设置路由id spring.cloud.gateway.routes[1].id=service-dict #设置路由的uri spring.cloud.gateway.routes[1].uri=lb://service-dict #设置路由断言,代理servicerId为auth-service的/auth/路径 spring.cloud.gateway.routes[1].predicates= Path=/*/dict/**
上面的配置文件中,主要看 spring.cloud.gateway.routes 的配置,这里是数组,分别配置了两个路由规则,一个用来转发给 service_user 服务,第二个用来转发给 service_dict 服务。
同样要给 gateway 创建一个启动类,启动类的代码如下:
@SpringBootApplication @EnableDiscoveryClient public class ServerGatewayApplication { public static void main(String[] args) { SpringApplication.run(ServerGatewayApplication.class, args); } }
这样就可以启动我们的 gateway 了,gateway 的端口号为 7000。
五、测试前端调用
service-user、service-dict 和 service-gateway 已经启动并注册到了 Nacos 中,但是现在我们并不能测试我们的前端页面,原因是前端页面的地址使用的是 Nginx 的端口,而 Nginx 的规则仍然是直接转发给两个服务,我们需要修改 Nginx 的配置,修改如下:
server { listen 9001; server_name localhost; location ~ /user/ { proxy_pass http://localhost:7000; } location ~ /dict/ { proxy_pass http://localhost:7000; } }
可以看到,Nginx 将两个请求转发给了 localhost:7000,也就是转发给了我们的网关。那么,我们来测试我们的前端页面。通过 F12 的调试窗口来进行查看。如下图所示。
可以看到,我们的请求同样成功了。前端页面请求 localhost:9001 也就是 Nginx 的端口号,然后 Nginx 转发给 网关,最后网关路由到具体的服务,这样就完成了一次前端请求服务的调用。如下图所示。
同样的,我们可以让 Ajax 直接调用网关来访问服务,这里就不再进行演示了,大家可以自行测试。
六、总结
本篇文章通过一个简单的 Demo 完成了一个简单的 网关功能,该网关具有 处理跨域请求 和 路由转发 的功能。当然了我们这个功能过于的简单,但是大家可以自己进行扩展。比如可以类似如下图所示。
gateway、service_user 和 service_dict 同时部署多台,Nginx 通过负载均衡策略将请求转发到任意一台网关,网关再将请求分发到任意一台具体的服务上。如果是这样做,那么我们的 Demo 看起来就更有些意思了。