Brief introduction
Services Gateway
Services Gateway is a micro-service architecture an integral part. REST API provides a process by serving out a unified gateway system, in addition to have the service routing, load balancing function, it also has access control and other functions. Spring Cloud Netflix in Zuul has served as such a role, the role of providing protection for the front door micro-service architecture, while the authority to control these heavy content migration to non-business logic routing service level, so that the body can have more clustered service high reusability and testability.
Route Forwarding Services Gateway = + filter
- Route Forwarding: Receive all external requests forwarded to the backend of micro-services go up; for example, / can be mapped to your Web application, / api / users mapped to user services, and / api / shop mapped to store service.
- Filters: You can complete a series of cross-service gateway function, such as checking permissions, limiting and monitoring, which can be done (in fact, routing forwarding is achieved through the filter) through the filter.
Zuul
Netflix Zuul using the following operations:
- Authenticate
- Insight
- pressure test
- Canary test
- Dynamic Routing
- Migration Services
- Load shedding
- Safety
- Static response processing
- Active / Active Traffic Management
Zuul, Ribbon and Eureka can be combined with intelligent routing and load balancing functions; gateway API interface for all services consistent aggregation, unified external exposure. When the outside world to call API interface, do not need to know the complexity of the micro-service system for each service call each other to protect the internal micro-services API interface unit; gateway can do user authentication and certification authority, prevent illegal operation requested API interface; gateway implement monitoring, real-time log output record request; gateway traffic monitoring can be achieved, in the case of high traffic, to service degradation; the API interfaces separating out from the internal service, convenient to do the test.
Zuul achieved by Servlet, be controlled by custom request ZuulServlet. The core is a series of filters, the filter may be performed during a series of initiating the request and returns a response Http. Zuul taken a dynamic read, compile and run these filters. Between the filter can not communicate directly, but rather through RequestContext shared data objects, each request creates a RequestContext object.
Zuul life cycle as shown below. Request When a client request to enter Zuul gateway service, the first gateway into the "pre filter", a series of verify operation or judgment. And then to "routing filter" routing forwarding, for example to a specific service logic processing, data is returned. When the specific service process is completed, and finally processed by a "post filter", the type of processor after processing is complete, the Request message back to the client. The implementation of "error filter" in the other stages errors. In addition to the default filter type, Zuul also allows us to create a custom filter type. For example, we can have customized a STATIC type of filter, generated in response Zuul directly, without the rear forwards the request to the micro-services.
Create a service gateway
Add file dependencies POM.xml
<?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>com.springcloud</groupId>
<artifactId>springcloud-root</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>springcloud-zuul</artifactId>
<name>springcloud-zuul</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application.yml configuration file
- application.yml
spring:
application:
name: springcloud-zuul
freemarker:
prefer-file-system-access: false
security:
user:
name: admin
password: 123456
server:
port: 8120
eureka:
instance:
hostname: eureka-zuul.com
instance-id: eureka-zuul
client:
service-url:
defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer1.com:8897/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer2.com:8898/eureka/,http://${spring.security.user.name}:${spring.security.user.password}@eureka-peer3.com:8899/eureka/
zuul:
#接口前缀(v1作为版本号)
prefix: /v1
routes:
hiapi:
path: /hiapi/**
serviceId: springcloud-eureka-provider
ribbonapi:
path: /ribbonapi/**
serviceId: springcloud-ribbon
feignapi:
path: /feignapi/**
serviceId: springcloud-feign
Modify C: \ Windows \ System32 \ drivers \ etc \ hosts
127.0.0.1 eureka-zuul.com
Disables the specified Filter
You can configure the application.yml need to disable the filter, format
zuul.<SimpleClassName>.<filterType>.disable=true
For example, to disable org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter is set
zuul:
SendResponseFilter:
post:
disable: true
Add a service gateway startup class
- ZuulApplication.java
Add comments @EnableZuulProxy
package org.springcloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
In order to start the project
springcloud-eureka-cluster-peer1
springcloud-eureka-cluster-peer2
springcloud-eureka-cluster-peer3
springcloud-eureka-provider1
springcloud-eureka-provider2
springcloud-eureka-provider3
springcloud-ribbon
springcloud-feign
springcloud-zuul
-
Browser numerous visits http://eureka-zuul.com:8120/v1/hiapi/hi?name=zhaojq
Zuul routing forwarding do load balancing -
Browser numerous visits http://eureka-zuul.com:8120/v1/ribbonapi/hi?name=zhaojq
Zuul and Ribbon combined to achieve load balancing (random strategy) -
Browser numerous visits http://eureka-zuul.com:8120/v1/feignapi/hi?name=zhaojq
Zuul and Feign combined to achieve load balancing (random strategy)
Configuring fuse on the service gateway Zuul
Fuses need to implement functions to achieve FallbackProvider interface, the interfaces of the two methods, one is getRoute (), which specifies the function of the fuse routing services are used; Another method fallbackResponse () is executed when the function of the fuse enters logic.
- ZuulHystrix.java
If you need to service all the routes are added fuse function, need to return on getRoute () method "*" character matches
package org.springcloud.zuul;
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;
@Component
public class ZuulHystrix implements FallbackProvider {
@Override
//指定熔断器功能应用于哪些路由的服务
public String getRoute() {
//return "springcloud-eureka-provider";
return "*";
}
@Override
//进入熔断器功能时执行的逻辑
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
System.out.println("route:"+route);
System.out.println("exception:"+cause.getMessage());
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 {
return new ByteArrayInputStream("eureka-provider is down!! this is the fallback.".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
After all the normal start, stop springcloud-eureka-provider2 providers, port: 8002 service
access to the command window curl http://eureka-zuul.com:8120/v1/hiapi/hi?name=zhaojq, circuit breakers already in force, Tip: service provider hung up
Custom filter Zuul Filter
Zuul the filter 4 comprising
- PRE Filter: request routing is performed, can be done to secure verification before specific services, such as authentication, parameter validation.
- ROUTING Filter: It is used to route the request to a specific micro service instance. Http Client default for network requests.
- POST filters: the micro-in request has been performed after the service route. It can be used to collect statistics, indicators, and the response to the client.
- ERROR Filters: executed when the other filter error has occurred.
Zuul default filter implementation
Types of | order | filter | Features |
---|---|---|---|
pre | -3 | ServletDetectionFilter | Marking process Servlet type |
pre | -2 | Servlet30WrapperFilter | Packing HttpServletRequest request |
pre | -1 | FormBodyWrapperFilter | Packing request body |
route | 1 | DebugFilter | Mark debug flag |
route | 5 | PreDecorationFilter | Processing request context for subsequent use |
route | 10 | RibbonRoutingFilter | serviceId request forwarding |
route | 100 | SimpleHostRoutingFilter | url request forwarding |
route | 500 | SendForwardFilter | forward the request to forward |
post | 0 | Send Error Filter | Error processing request response |
post | 1000 | SendResponseFilter | Normal processing request response |
Implementing custom filters need to inherit ZuulFilter, ZuulFilter implement the abstract methods, including filterType (), filterOrder () and the IZuulFilter shouldFilter () and run () method.
- filterType () is a filter type, there are 4 types: pre, post, routing and error.
- filterOrder () is a filter order, it is the value of an int type, the smaller the value, the earlier the execution of the filter.
- shouldFilter () indicating whether to execute the filter logic, represent true executed, to false means that no process is executed if true run ().
- run () method is specific logic filtering. Parameter check request in the present embodiment whether the password or token pass this parameter, if there is no transmission, requesting a specific service instance to not routed directly returns a response with a status code 401.
TokenFilter filter
- TokenFilter.java
package org.springcloud.zuul;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
public class TokenFilter extends ZuulFilter {
private static Logger LOGGER=LoggerFactory.getLogger(TokenFilter.class);
@Override
//定义filter的类型,有pre、route、post、error四种
public String filterType() {
//可以在请求被路由之前调用
return "pre";
}
@Override
//定义filter的顺序,数字越小表示顺序越高,越先执行
public int filterOrder() {
return 0;
}
@Override
//表示是否需要执行该filter,true表示执行,false表示不执行
public boolean shouldFilter() {
return true;
}
@Override
//filter需要执行的具体操作
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
LOGGER.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString());
//获取请求的参数
String token = request.getParameter("token");
if (StringUtils.isNotBlank(token)) {
//对请求进行路由
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
LOGGER.warn("token is empty");
//不对请求进行路由
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("token is empty");
} catch (IOException e) {
e.printStackTrace();
}
ctx.set("isSuccess", false);
return null;
}
}
}
Enable the filter, start programs such ZuulFilterApplication add Bean
- ZuulApplication.java
package org.springcloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
@Bean
public TokenFilter TokenFilter() {
return new TokenFilter();
}
}
After restarting the project, visit http://eureka-zuul.com:8120/v1/hiapi/hi?name=zhaojq
prompted token is empty.
Access http://eureka-zuul.com:8120/v1/hiapi/hi?name=zhaojq&token=cc
seen, after injection of the Bean TokenFilter IOC container, filtering the request, and a request routing logic determines before forwarding .
Tip token is empty display twice error
The custom TokenFilter of @Component cancel it, do not let the Spring container management.
PasswordFilter filter
- PasswordFilter.java
package org.springcloud.zuul;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
public class PasswordFilter extends ZuulFilter {
private final Logger LOGGER = LoggerFactory.getLogger(PasswordFilter.class);
@Override
public String filterType() {
//请求已被路由到微服务后执行
return "post";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
//判断上一个过滤器结果为true,否则就不走下面过滤器,直接跳过后面的所有过滤器并返回 上一个过滤器不通过的结果
return (boolean) ctx.get("isSuccess");
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
LOGGER.info("--->>> PasswordFilter {},{}", request.getMethod(), request.getRequestURL().toString());
String username = request.getParameter("password");
if (null != username && username.equals("123456")) {
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
ctx.set("isSuccess", true);
return null;
} else {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("The password cannot be empty");
} catch (IOException e) {
e.printStackTrace();
}
ctx.set("isSuccess", false);
return null;
}
}
}
Enable the filter, start programs such ZuulFilterApplication add Bean
- ZuulApplication.java
package org.springcloud.zuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
@Bean
public TokenFilter TokenFilter() {
return new TokenFilter();
}
@Bean
public PasswordFilter PasswordFilter() {
return new PasswordFilter();
}
}
Access http://eureka-zuul.com:8120/v1/hiapi/hi?name=zhaojq&token=cc&password=123456