专栏首页品茗ITSpringCloud技术指南系列(十一)API网关之Zuul使用

SpringCloud技术指南系列(十一)API网关之Zuul使用

SpringCloud技术指南系列(十一)API网关之Zuul使用

一、概述

API网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的Facade模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要经过它来进行调度和过滤。它除了要实现请求路由、 负载均衡、 校验过滤等功能之外,还需要更多能力,比如与服务治理框架的结合、请求转发时的熔断机制、服务的聚合等一系列高级功能。

在SpringCloud全家桶中,API网关有Zuul和gateway两种实现。

  1. zuul进来逐渐被gateway取代。
  2. zuul可以整合进任何SpringBoot应用
  3. gateway基于异步非阻塞模型,使用的netty+webflux实现,不能加入web依赖,默认加载加入webflux依赖。
  4. Spring Cloud zuul使用的仍是zuul 1.x,zuul 2.x也是异步非阻塞的。
  5. 选用zuul还是gateway,要看使用场景,如果在已有的非WebFlux项目使用,要用zuul。单纯的API网关独立部署,建议gateway。

代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springcloud.html中的EurekaZuul、ZkZuul和ConsulZuul组件中查看,并下载。分别对应三种不同的服务注册方式。

**如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以<a

href="https://jq.qq.com/?_wv=1027&k=52sgH1J"

target="_blank">

加入我们的java学习圈,点击即可加入

</a>

,共同学习,节约学习时间,减少很多在学习中遇到的难题。**

二、项目配置

本篇的配置基于服务注册发现的项目基础上,并选择Consul + zuul为例讲解如何使用zuul做API网关。至于(Eureka + zuul)和 (zookeeper + zuul)写法上和(consul + zuul)是一样的,不再分开章节描述。

这里选择Consul + zuul为例,是因为它在配置中有一个坑,其他两个倒是没有,下面配置时会着重说明下它。

可以参考我前面的文章做对比:

《SpringCloud技术指南系列(五)服务注册发现之Consul服务调用》

《SpringCloud技术指南系列(三)服务注册发现之Eureka服务调用》

《SpringCloud技术指南系列(七)服务注册发现之Zookeeper服务调用》

2.1 引入依赖

需要在建立好的项目中引入spring-cloud-starter-netflix-zuul.

本篇是在consul的服务发现基础上进行zuul的配置,因此还需要引入consul相关配置。

依赖如下:

<?xml version="1.0"?>
<project
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.pomit</groupId>
		<artifactId>springcloudwork</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>ConsulZuul</artifactId>
	<name>ConsulZuul</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<maven-jar-plugin.version>2.6</maven-jar-plugin.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
		<!-- 使用feign时才用的上 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-openfeign</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>
	</dependencies>
</project>

父模块pom文件可以在https://www.pomit.cn/spring/SpringCloudWork/pom.xml获取。

2.2 配置文件

这里使用yaml文件写配置,配置文件application.yml:

application.yml:

server:
   port: 8816
spring:
   application:
      name: consulZuul
   cloud:
      consul:
         host: 127.0.0.1
         port: 8500
         discovery:
            prefer-ip-address: true
            healthCheckPath: /consulHeart/health
zuul:
   ignoredServices: 
   routes:
      util:
         path: /util/**
         sensitiveHeaders: 
         serviceId: consulServer
      search:
         path: /search/**
         url: https://cn.bing.com/

这里,表示API网关在8816端口监听,名字是consulZuul。

  • spring.cloud.consul开头的配置时consul服务注册发现的配置。前面章节已经有说明。
  • zuul.ignoredServices是要忽略的服务名称,这个地方有个坑,就是如果你在应用中有/consul这样的controller,它就会自动请求consul的8300端口,然后就导致失败,所以建议这个地址加个ignoredServices: consul
  • zuul.routes.util 这个表示,请求到/util这个路径时需要的处理,path是标明路径,sensitiveHeaders是标明传输的http头信息,serviceId是标明这个是consul上的服务,通过这个id找到对应的服务地址并转发。
  • zuul.routes.search 这个表示,请求到/search的配置,我这里是向外转发到必应做搜索。

三、Zuul服务不可用降级

Zuul默认整合了hystrix做熔断。当请求次数失败次数过多(服务中途挂掉,试验时是5次),将不再请求,直接返回CommonFallbackProvider配置的内容。

当然,只要服务不可用,都会调用CommonFallbackProvider的方法返回信息,这就是服务降级。hystrix熔断是防止不断请求无效服务浪费资源,甚至影响其他服务。

CommonFallbackProvider :

package cn.pomit.springbootwork.config.client;
package cn.pomit.springbootwork.consulzuul.config;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

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 com.fasterxml.jackson.databind.ObjectMapper;

import cn.pomit.springbootwork.consulzuul.model.ResultModel;

@Component
public class CommonFallbackProvider implements FallbackProvider {
	@Override
	public String getRoute() {
		return "*";
	}

	@Override
	public ClientHttpResponse fallbackResponse(String route, Throwable throwable) {
		throwable.printStackTrace();
		return new ClientHttpResponse() {
			@Override
			public HttpStatus getStatusCode() throws IOException {
				return HttpStatus.OK;
			}

			@Override
			public int getRawStatusCode() throws IOException {
				return 200;
			}

			@Override
			public String getStatusText() throws IOException {
				return "OK";
			}

			@Override
			public void close() {

			}

			@Override
			public InputStream getBody() throws IOException {
				ResultModel rm = ResultModel.error("服务咱不可用,请稍后重试!");
				ObjectMapper mapper = new ObjectMapper();
				return new ByteArrayInputStream(mapper.writeValueAsString(rm).getBytes());
			}

			@Override
			public HttpHeaders getHeaders() {
				HttpHeaders headers = new HttpHeaders();
				headers.setContentType(MediaType.APPLICATION_JSON);
				return headers;
			}
		};
	}

}

四、开启Zuul代理

在启动类似使用@EnableZuulProxy开启即可。

ConsulZuulApplication :

package cn.pomit.springbootwork.consulzuul;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableZuulProxy
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ConsulZuulApplication {
	public static void main(String[] args) {
		SpringApplication.run(ConsulZuulApplication.class, args);
	}
	
	@Bean
	@LoadBalanced
	RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

五、其他web

我们仍可以写自己的web服务,和zuul的转发互不影响,但是路径别重复了。

ConsulZuulRest :

package cn.pomit.springbootwork.consulzuul.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.springbootwork.consulzuul.model.ResultModel;

@RestController
@RequestMapping("/consulZuul")
public class ConsulZuulRest {
	
	@RequestMapping(value = "/test", method = { RequestMethod.GET })
	public ResultModel ip() {
		return ResultModel.ok("非路由测试");
	}
}

六、Consul的健康检测

这个是使用consul做注册中心才需要的。

package cn.pomit.springbootwork.consulzuul.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/consulHeart")
public class HealthWeb {

	@RequestMapping(value = "health", method = { RequestMethod.GET })
	public String health() {
		return "check health";
	}
	
}

七、使用到的实体

ResultModel:

package cn.pomit.springbootwork.consulzuul.model;

/**
 * @author cff
 */
public class ResultModel {

	private String errorCode;
	private String message;
	private Object data;

	public ResultModel() {

	}

	public ResultModel(String errorCode, String message) {
		this.errorCode = errorCode;
		this.message = message;
	}

	public ResultModel(String errorCode, String message, Object data) {
		this.errorCode = errorCode;
		this.message = message;
		this.data = data;
	}

	public String geterrorCode() {
		return errorCode;
	}

	public void seterrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public static ResultModel ok() {
		return new ResultModel("0000","成功");
	}

	public static ResultModel ok(Object data) {
		return new ResultModel("0000","成功", data);
	}

	public static ResultModel error() {
		return new ResultModel("1111","失败");
	}

	public static ResultModel error(String msg) {
		return new ResultModel("1111","失败", msg);
	}

	public static ResultModel error(String msg, Object data) {
		return new ResultModel("1111", msg, data);
	}
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringCloud技术指南系列(十二)API网关之Gateway使用

    API网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的Facade模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户端访问都需要...

    品茗IT
  • SpringCloud微服务实战系列(二十)Ouath2在真实场景中的应用之客户端接入(第二种写法)

    在《SpringCloud微服务实战系列(十七)Ouath2在真实场景中的应用之资源服务器》]中

    品茗IT
  • Spring和Security整合详解

    Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决...

    品茗IT
  • Redis之Spring实现发布订阅 原

    注:Redis版本是4.0;Spring版本4.3.11;Redis client版本2.9.0。

    克虏伯
  • 记一次学习SpringBoot RequestBodyAdvice ResponseBodyAdvice RestControllerAdvice【技能篇】

    今天老板给我了一套代码,然后我就拿过去研究,代码的风格是SSM + Shiro + nginx + SpringBoot的MVC架构风格,springboot,...

    奕仁
  • SpringBoot集成Swagger2

    在一些接口项目中,API的使用很频繁,所以一款API在线文档生成和测试工具非常有必要。而Swagger UI就是这么一款很实用的在线工具 本博客介绍如何在公司...

    SmileNicky
  • ES-使用springData来操作es 原

    用户5927264
  • Spring Boot系列——7步集成RabbitMQ

    RabbitMQ是一种我们经常使用的消息中间件,通过RabbitMQ可以帮助我们实现异步、削峰的目的。

    JackieZheng
  • zuul集成apollo动态刷新配置

    一笠风雨任生平
  • Spring 中实现事务的方式

    Spring 并不直接支持事务,只有当数据库支持事务时,Spring 才支持事务,Spring 只不过简化了开发人员实现事务的步骤。 Spring 提供了两种...

    水货程序员

扫码关注云+社区

领取腾讯云代金券