SpringCloud-使用路由网关统一访问接口(附代码下载)
场景
springcloud-使用熔断器仪表盘监控熔断:
https://blog.csdn.net/badao_liumang_qizhi/article/details/102673599
springcloud -创建统一的依赖管理:
https://blog.csdn.net/badao_liumang_qizhi/article/details/102530574
上面在实现了使用熔断仪表盘进行监控熔断后,使用路由网关统一访问接口。
api网关
api网关负责请求路由、组合和协议转发。所有的客户端请求首先要通过api网关,之后请求被路由到适当的服务。
api网关通常会调用多个微服务和聚合结果来处理一个请求。它可以在web协议(如http和websocket)和利用于内部的非web友好协议之间进行转换。
负载均衡方式
在spring cloud微服务系统中,一种常见的负载均衡方式是:客户端的请求先经过负载均衡(zuul、nginx),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件放在git仓库,方便开发人员随时改配置。
zuul简介
zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分。
zuul默认和ribbon结合实现了负载均衡的功能。
注:
博客:
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
实现
参考上面构建项目的方式,依次建立目录hello-spring-cloud-zuul目录以及在
目录下新建pom.xml,并将其托管。然后新建src/main/java目录和src/main/resources目录并分别进行目录设置。
然后在java下新建包,包下新建启动类,在resources下新建配置文件application.yml。
完成后的目录为:
pom.xml代码
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>com.badao</groupid> <artifactid>hello-spring-cloud-dependencies</artifactid> <version>1.0.0-snapshot</version> <relativepath>../hello-spring-cloud-dependencies/pom.xml</relativepath> </parent> <artifactid>hello-spring-cloud-zuul</artifactid> <packaging>jar</packaging> <name>hello-spring-cloud-zuul</name> <url>https://blog.csdn.net/badao_liumang_qizhi</url> <inceptionyear>2019-now</inceptionyear> <dependencies> <!-- spring boot begin --> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-tomcat</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-actuator</artifactid> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> </dependency> <!-- spring boot end --> <!-- spring cloud begin --> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-server</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-zuul</artifactid> </dependency> <!-- spring cloud end --> </dependencies> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <configuration> <mainclass>com.badao.hello.spring.cloud.zuul.zuulapplication</mainclass> </configuration> </plugin> </plugins> </build> </project>
配置文件application.yml代码
spring: application: name: hello-spring-cloud-zuul server: port: 8769 eureka: client: serviceurl: defaultzone: http://localhost:8761/eureka/ zuul: routes: api-a: path: /api/a/** serviceid: hello-spring-cloud-web-admin-ribbon api-b: path: /api/b/** serviceid: hello-spring-cloud-web-admin-feign
注:
以 /api/a 开头的请求都转发给 hello-spring-cloud-web-admin-ribbon
服务
以 /api/b 开头的请求都转发给 hello-spring-cloud-web-admin-feign
服务
其中routes是固定的,但是api-a与api-b是自己定义的。
在自定义的路由中,path代表请求的路径,serviceid代表真正映射的服务的id。
在path中**代表通配符,即以/api/a开头的都会请求同组内的serviceid所对应的服务。
然后在包下新建com.badao.hello.spring.cloud.zuul包,并在包下新建zuulapplication启动类
package com.badao.hello.spring.cloud.zuul; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.cloud.netflix.eureka.enableeurekaclient; import org.springframework.cloud.netflix.zuul.enablezuulproxy; @springbootapplication @enableeurekaclient @enablezuulproxy public class zuulapplication { public static void main(string[] args) { springapplication.run(zuulapplication.class, args); } }
至此整个服务体系的结构如下
效果
我们依次启动eureka服务、服务提供者、两个服务消费者、zuul的application启动类
然后打开浏览器,输入:
打开eureka的服务与注册发现中心,发现全部被注册并发现
然后再打开浏览器输入:
http://localhost:8769/api/a/hi?message=hellozuulfrombadao
再打开浏览器输入:
http://localhost:8769/api/b/hi?message=hellozuulfrombadao
则zuul的路由配置功能配置成功。
配置网关路由失败时的回调
有时如果因为网络、内存等原因导致网关路由失败,则需要配置失败时的回调。
再新建fallback包,包下新建webadminfeignfallbackprovider
package com.badao.hello.spring.cloud.zuul.fallback; import com.fasterxml.jackson.databind.objectmapper; import org.springframework.cloud.netflix.zuul.filters.route.fallbackprovider; import org.springframework.http.httpheaders; import org.springframework.http.httpstatus; import org.springframework.http.mediatype; import org.springframework.http.client.clienthttpresponse; import org.springframework.stereotype.component; import java.io.bytearrayinputstream; import java.io.ioexception; import java.io.inputstream; import java.util.hashmap; import java.util.map; @component public class webadminfeignfallbackprovider implements fallbackprovider { @override public string getroute() { // serviceid,如果需要所有调用都支持回退,则 return "*" 或 return null return "hello-spring-cloud-web-admin-feign"; } /** * 如果请求服务失败,则返回指定的信息给调用者 * @param route * @param cause * @return */ @override public clienthttpresponse fallbackresponse(string route, throwable cause) { return new clienthttpresponse() { /** * 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的, * 不应该把 api 的 404,500 等问题抛给客户端 * 网关和 api 服务集群对于客户端来说是黑盒 * @return * @throws ioexception */ @override public httpstatus getstatuscode() throws ioexception { return httpstatus.ok; } @override public int getrawstatuscode() throws ioexception { return httpstatus.ok.value(); } @override public string getstatustext() throws ioexception { return httpstatus.ok.getreasonphrase(); } @override public void close() { } @override public inputstream getbody() throws ioexception { objectmapper objectmapper = new objectmapper(); map<string, object> map = new hashmap<>(); map.put("status", 200); map.put("message", "无法连接,请检查您的网络"); return new bytearrayinputstream(objectmapper.writevalueasstring(map).getbytes("utf-8")); } @override public httpheaders getheaders() { httpheaders headers = new httpheaders(); // 和 getbody 中的内容编码一致 headers.setcontenttype(mediatype.application_json_utf8); return headers; } }; } }