对于微服务之间的调用,我们一般不需要做身份验证,但是如果是外部请求到微服务,那么就需要进行身份验证了,比如app或PC端请求登录,请求发到User服务,则要进行身份验证;再比如app或PC端下单,则要请求Order服务,你是不是发现了一个问题,外部请求请求到哪个微服务,哪个微服务就要进行身份认证,这无疑是增加了每个微服务的负担和复杂性。
如果我们用一个微服务专门来做身份验证,验证完成之后,将请求转发到其他微服务,各个微服务之间的相互调用就不再需要做身份认证了,这样是不是就解决上面的问题了。
这就是Spring Cloud Zuul的作用之一。
Zuul支持前置身份认证、审查、监控、动态路由等等功能。
我们来演示一下,gateway怎样实现路由分发功能,这也是gateway最基本和重要的功能,也就是外部请求统一都请求到gateway服务,由gateway来统一分发请求到各个微服务。
实操O(∩_∩)O
1、新建一个maven项目,名叫gateway
<?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">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway</artifactId>
<groupId>com.itzhimei</groupId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
这里重点引入了Zuul的gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
2、新建应用启动类
package com.itzhimei.gateway;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@SpringBootApplication
public class GatewayApplication {
private static final Logger LOGGER = LoggerFactory.getLogger(GatewayApplication.class);
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
LOGGER.info("网关服务启动完成...");
}
}
这里使用了注解@EnableZuulProxy,让该项目支持了网关功能
3、添加配置bootstrap.yml和bootstrap-dev.yml
bootstrap.yml内容:
spring:
application:
name: gateway
profiles:
active: dev
cloud:
config:
discovery:
enabled: true
serviceId: config
# profile: dev
label: gateway
server:
port: 3333
eureka:
instance:
prefer-ip-address: true #注册时使用ip地址
这里的配置和前面章节的作用是一样的,指定自己的服务serviceId,指定配置中心。
bootstrap-dev.yml内容:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
这里是指定向哪里注册服务
4、路由分发功能
我们在gateway服务的bootstrap.yml文件中再添加一些配置:
zuul:
routes:
api-user:
path: /api-service-a/**
service-id: service-a
这些配置就是一个最简单的路由映射配置。
path: /api-service-a/** 表示请求格式是:ip或域名:端口/api-service-a/任意内容,映射到service-id是service-a的服务上。
也就是例如 localhost:3333/api-service-a/api/user/getApiInfo,请求应该先到网关服务,然后网关服务根据配置,将请求转发到service-a。
为了完成示例,我们在service-a服务中在添加一个controller,代码如下:
package com.itzhimei.servicea.controller.api;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(("/api/user"))
public class ApiUserController {
@Value("${user.name}")
String name;
@Value("${user.age}")
int age;
@GetMapping(value = "/getApiInfo")
public String getInfo(){
return "名字是:"+name+",年龄是:"+age+1;
}
}
现在把服务都启动,测试一下效果。
请求地址:localhost:3333/api-service-a/api/user/getApiInfo
输出结果:名字是:张三,年龄是:21
到这里,网关服务最重要的一个路由转发功能就完成了。
我们这里其实还可以把gateway的路由映射配置,放到配置中心来统一管理,动手试一下。