什么是网关
在微服务架构中,通常会有多个服务提供者。设想一个电商系统,可能会有商品、订单、支付、用户等多个类型的服务,
而每个类型的服务数量也会随着整个系统体量的增大也会随之增长和变更。作为UI端,在展示页面时可能需要从多个微服务中聚合数据,
而且服务的划分位置结构可能会有所改变。网关就可以对外暴露聚合API,屏蔽内部微服务的微小变动,保持整个系统的稳定性。
当然这只是网关众多功能中的一部分,它还可以做负载均衡,统一鉴权,协议转换,监控监测等一系列功能
什么是zuul
Zuul是Spring Cloud全家桶中的微服务API网关。
所有从设备或网站来的请求都会经过Zuul到达后端的Netflix应用程序。作为一个边界性质的应用程序,
Zuul提供了动态路由、监控、弹性负载和安全功能。
Zuul底层利用各种filter实现如下功能:
认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
性能监测 在服务边在这里插入代码片界追踪并统计数据,提供精确的生产视图。
动态路由 根据需要将请求动态路由到后端集群。
压力测试 逐渐增加对集群的流量以了解其性能。
负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
静态资源处理 直接在边界返回某些响应。
搭建环境
pom.xml
<dependencies>
<dependency>
<groupId>com.jwxt</groupId>
<artifactId>jwxt-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<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-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR2</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>
application,yml
server:
port: 56700
spring:
application:
name: my-zuul
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/kytms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
#url: jdbc:mysql://192.168.5.240:3306/kytms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
redis:
database: 0
host: 127.0.0.1
port: 6379
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
timeout: 50000
eureka:
client:
service-url:
defaultZone: http://localhost:56798/eureka/,http://localhost:56799/eureka/
instance:
prefer-ip-address: true
instance-id: my_zuul8088
#zuul: 也是配置路由访问的一种方式
# routes:
# my-system: /system/**
zuul:
routes:
jwxt-teacher:
path: /teacher/** #访问的路径
service-id: jwxt-teacher #访问的服务
jwxt-learner:
path: /student/**
service-id: jwxt-learner
ignored-services: '*'
#ignored-patterns: /**/findOne/** #忽略带有findOne的请求(就不能再访问带有findOne的请求)
#prefix: /api #访问路径的前缀,需要多加一层的/api
ribbon:
ReadTimeout: 60000
ConnectTimeout: 60000
eureka:
enabled: true
拦截器
package com.jwxt.filter;
import com.alibaba.fastjson.JSON;
import com.jwxt.response.Result;
import com.jwxt.response.ResultCode;
import com.jwxt.utils.JwtUtils;
import com.jwxt.utils.RedisUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyZuulFilter extends ZuulFilter {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
HttpServletResponse response = currentContext.getResponse();
StringBuffer requestURL = request.getRequestURL();
if (requestURL.toString().contains("teacher/login")) return null;
//String authorization = request.getHeader("Authorization");
String authorization = request.getParameter("token");
if (!StringUtils.isEmpty(authorization) && authorization.startsWith("Bearer")) {
String token = authorization.replace("Bearer ","");
Claims claims = JwtUtils.parseJwt(token);
if (claims == null) {
access_denied();
return null;
}else{
redisTemplate.opsForValue().set("user_claims",claims);
/* if (redisTemplate.hasKey(claims.getId())) {
access_denied();
return null;
}*/
return null;
}
/*
Cookie cookie = ServletUtil.getCookie(request, "token_key");
if (cookie == null) {
access_denied();
return null;
}*/
} else {
access_denied();
return null;
}
}
//拒绝访问
protected void access_denied(){
RequestContext requestContext = RequestContext.getCurrentContext();
//得到response
HttpServletResponse response = requestContext.getResponse();
//拒绝访问
requestContext.setSendZuulResponse(false);
//设置响应代码
requestContext.setResponseStatusCode(200);
//构建响应的信息
Result responseResult = new Result(ResultCode.NO_EXIST_PERMISSION);
//转成json
String jsonString = JSON.toJSONString(responseResult);
requestContext.setResponseBody(jsonString);
//转成json,设置contentType
response.setContentType("application/json;charset=utf-8");
}
}
跨域
package com.jwxt;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
/**
* 跨域配置
*/
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*")); //http:www.a.com
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300l);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
启动类
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class MyZuulApplication {
public static void main(String[] args) {
SpringApplication.run(MyZuulApplication.class,args);
}
}