一. Zuul网关
1. 创建工程 并导入依赖
添加依赖
<!-- zuul网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<!-- 计数器 -->
<dependency>
<groupId>com.marcosbarbero.cloud</groupId>
<artifactId>spring-cloud-zuul-ratelimit</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
2. application.yml 配置文件
server:
port: 7003
spring:
application:
name: zuul-server
eureka: # 注册中心
client:
service-url:
defaultZone: http://localhost:7001/eureka/ #,http://localhost:7002/eureka/ #添加到的eureka注册中心的地址
instance:
prefer-ip-address: true #在eureka地址页面中显示微服务的ip地址和端口
instance-id: ${spring.cloud.client.ip-address}:${server.port} #设置发送心跳时间间隔
lease-renewal-interval-in-seconds: 5 #设置没有发送心跳 微服务在eureka中保存的最大时间
lease-expiration-duration-in-seconds: 10
# zuul 网关
zuul:
routes:
user-server: # 这里是路由id,随意写
path: /** # 这里是映射路径 user 是api/user/get 此处写api/** 实际的就为api/api/user/get
serviceId: user-server #配置转发的微服务名称
order-server:
path: /**
serviceId: order-server
3. 启动类添加注解
4. 依次启动服务
5. 进入浏览器访问测试
链接:http://localhost:7003/userserver/findUserOrder?uid=2
展示此数据就说明成功了
1. ZuulFilter简介
以通过配置 urlPatterns 来拦截对应的请求。而 Zuul 中的过滤器总共有 4 种类型,且每种类型都有对应的使用场景。
- PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
- ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfifilx Ribbon请求微服务。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP
Header、收集统计信息和指标、将响应从微服务发送给客户端等。 - ERROR:在其他阶段发生错误时执行该过滤器。
2. 在filters包下创建PowerFilter类
package com.ddz.filters;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class PowerFilter extends ZuulFilter {
/* 过滤器类型,可选值有 pre、route、post、error */
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/* 过滤器的执行顺序,数值越小,优先级越高 */
@Override
public int filterOrder() {
return 0;
}
/* 是否执行该过滤器,true 为执行,false 为不执行,这个也可以利用配置中心来实现,达到动态的开启和关闭过滤器 */
@Override
public boolean shouldFilter() {
return true;
}
/* 业务逻辑,本次是判断请求的url是否带有token,没有则通过设置 ctx.setSendZuulResponse(false),
告诉 Zuul 不需要将当前请求转发到后端的服务了,通过setResponseBody 返回数据给客户端 */
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext(); //获取上下文
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token"); //获取token
if (token == null || "".equals(token)) {
context.setSendZuulResponse(false); // 过滤该请求
context.setResponseStatusCode(401); // 返回错误码
context.setResponseBody("{'msg':'401 account without'}"); // 返回错误信息
return "access";
}
return "next";
}
}
3. 再次访问网址
链接:http://localhost:7003/userserver/findUserOrder?uid=2
不带token访问
带token 访问
1. 在application.yml 配置文件添加!
zuul:
ratelimit:
enabled: true #开启限流
policies: # 多个微服务
user-server: # 上面写的路由id
limit: 3 #60s 内请求超过 3 次,服务端就抛出异常,60s 后可以恢复正常请求
quota: 30 #单位时间内允许访问的总时间(单位时间窗口期内,所有的请求的总时间不能超过这个时间限制)
refresh-interval: 10 #单位时间设置
type: origin #针对 IP 进行限流,不影响其他 IP
2. 再去连续快速的访问网址
链接:http://localhost:7003/userserver/findUserOrder?uid=2&token=1
以上错误信息,返回给前端易读性差下面对错误信息优化
3.再 controller 包下创建 ErrorController 错误信息控制器
package com.ddz.controller;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ErrorHander implements ErrorController {
@Override
public String getErrorPath() {
return "error";
}
/* 自定义的异常信息方法 */
@RequestMapping(value = "error")
public Map<String, Object> error() {
Map<String, Object> dto = new HashMap<>();
dto.put("msg", "计数器访问限流"); //提示信息
dto.put("code", 401); // 错误码
return dto;
}
}
4. 再去连续快速的访问网址
链接:http://localhost:7003/userserver/findUserOrder?uid=2&token=1
1. 在 filters 包下创建 LimitFilter 类
package com.ddz.filters;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class LimitFilter extends ZuulFilter {
// 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求
private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);
/* 过滤器类型,可选值有 pre、route、post、error */
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/* 过滤器的执行顺序,数值越小,优先级越高 */
@Override
public int filterOrder() {
return -5;
}
/* 是否执行该过滤器,true 为执行,false 为不执行,这个也可以利用配置中心来实现,达到动态的开启和关闭过滤器 */
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
//HttpServletRequest request = context.getRequest();
// tryAcquire() 只要能够马上获致到1个令牌,则返回true,不阻塞
// tryAcquire(5, 3, TimeUnit.SECONDS) 在3秒钟内可以获取到5个令牌,则返回true,不阻塞
// acquire(5) 获取到5个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
// acquire() 获取到1个令牌,否则一直等待,会阻塞,返回值为阻塞的时长
if (!RATE_LIMITER.tryAcquire()) {
context.getResponse().setContentType("application/json; charset=utf-8");
context.setSendZuulResponse(false); // false指当前请被过滤调
context.setResponseStatusCode(401); // 错误码
context.setResponseBody("{code:401,msg:'你限流了'}"); // 错误信息
return false;
}
return true;
}
/* 业务逻辑 */
@Override
public Object run() throws ZuulException {
return null;
}
}
2. 在 application.yml 中注释掉计数器限流配置
3. 去浏览器连续快速访问
链接:http://localhost:7003/userserver/findUserOrder?uid=2&token=1