有一点上篇文章忘了 讲述,nacos的加载优先级别最高。服务启动优先拉去配置信息。所以上一篇服务搭建我没有讲述在nacos 中心创建的配置文件



可以看到服务端口和注册中心都在配置文件中配置化

属性信息

上一篇我们讲了如何搭建网关zuul 服务。实现了基本的转发功能。这篇文章我们要讲述zuul过滤器的使用。和三个参数的使用

sensitiveHeaders 属性关键字声明:Spring Cloud微服务实战 书中意思为放行字段。而小编在官方文档查看到是忽略不放行的意思。请注意此处,看过Spring Cloud微服务实战同学可以用小编实例代码印证

  • ribbon-isolation-strategy

    • 隔离机制 Spring Cloud 默认的隔离机制hystrix 去做限流、熔断、隔离。一个是基于信号量。一个是基于线程池去完成

      • 信号量模式

        在该模式下,接收请求和执行下游依赖在同一个线程内完成,不存在线程上下文切换所带来的性能开销。默认信号量模式
      • 线程池

        在该模式下,用户请求会被提交到各自的线程池中执行,把执行每个下游服务的线程分离,从而达到资源隔离的作用。当线程池来不及处理并且请求队列塞满时,新进来的请求将快速失败,可以避免依赖问题扩散。
  • ignored-services
    • 忽略指定的服务
  • ignored—patterns
    • 忽略指定的url 路径
  • ignored-headers
    • 忽略指定的header 头部信息
  • sensitiveHeaders
    • 字段比较敏感,不希望传递给下游微服务。 设置空没有要忽略的敏感字段。全部传给下游服务

在上面ignored-headers 和 sensitiveHeaders 职责是有重叠的部分。其实他们是有着关系存在的。sensitiveHeaders的内容会最终合并到ignored-headers内。

验证一下 sensitiveHeaders 字段设置全区忽略 X-ABC

消费者服务 sensitiveHeaders 指定忽略 X-ABC,Authorization

服务提供者转发不做任何调整

在服务提供者 和 服务消费者 服务上。都创建一个 UrlFilter 拦截器

先设置一下 zuul的yml文件

zuul:
host:
# 目标主机的最大连接数,默认值为200
max-total-connections: 500
# 每个主机的初始连接数,默认值为20
max-per-route-connections: 100
routes:
discovery-server:
path: /server/**
serviceId: cloud-discovery-server
client-common:
path: /client/**
serviceId: cloud-discovery-client
sensitiveHeaders: X-ABC,X-Foo
# 所有路由的默认Hystrix隔离模式(ExecutionIsolationStrategy)为SEMAPHORE。如果此隔离模式是首选,则zuul.ribbonIsolationStrategy可以更改为THREAD
ribbon-isolation-strategy: thread
# 这个属性意思,* 忽略未指定的服务列表 有具体服务名称 忽略指定的服务
ignored-services: "*"
# 忽略指定的url 路径
ignored—patterns:
# 忽略指定的header 头部信息
ignored-headers: Authorization
# 字段比较敏感,不希望传递给下游微服务。 设置空没有要忽略的敏感字段。全部传给下游服务
sensitive-headers: X-ABC
ribbon:
eager-load:
# 强制加载,不设置会进行懒加载。spring 第一次请求会非常慢
enabled: true
package com.xian.cloud.filter;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration; /**
* <Description>
*
* @author xianliru@100tal.com
* @version 1.0
* @createDate 2019/10/29 13:57
*/
@WebFilter(filterName = "test",urlPatterns = "/*")
@Slf4j
public class UrlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.warn("UrlFilter init.......");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Enumeration<String> attributeNames = servletRequest.getAttributeNames();
HttpServletRequest req = (HttpServletRequest) servletRequest;
String requestURI = req.getRequestURI();
String header = req.getHeader("X-Foo");
String abc = req.getHeader("X-ABC");
String authorization = req.getHeader("Authorization");
String tom = req.getParameter("tom");
String mike = req.getParameter("mike");
log.warn("过滤器:请求地址"+requestURI);
log.warn("uuid:{}",header);
log.warn("abc uuid:{}",abc);
log.warn("authorization :{}",authorization);
log.warn("tom :{}",tom);
log.warn("mike :{}",mike);
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() {
log.warn(" 过滤器被销毁");
}
}

启动类上添加 @ServletComponentScan 用于扫描 过滤器 @WebFilter注解

package com.xian.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /**
* @Author: xlr
* @Date: Created in 2:44 PM 2019/10/27
*/
@EnableDiscoveryClient
@SpringBootApplication
//新增注解
@ServletComponentScan
public class DiscoveryServerApplication { public static void main(String[] args) {
SpringApplication.run(DiscoveryServerApplication.class, args);
}
}

使用postman 请求服务

服务端打印日志

2019-10-30 11:10:35.822  WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter          : 过滤器:请求地址/server/hello
2019-10-30 11:10:35.826 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : uuid:x-foo
2019-10-30 11:10:35.826 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : abc uuid:null
2019-10-30 11:10:35.827 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : authorization :null
2019-10-30 11:10:35.827 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : tom :null
2019-10-30 11:10:35.828 WARN 48882 --- [nio-9012-exec-8] com.xian.cloud.filter.UrlFilter : mike :null
2019-10-30 11:10:35.852 INFO 48882 --- [nio-9012-exec-8] c.x.cloud.controller.DiscoverCotroller : invoked name = xian age = 20

sensitive-headers、ignored-headers (abc、authorization都在zuul被过滤掉)全局设置生效。

我们再次请求client 服务接口

在看一下 客户端打印日志

2019-10-30 11:17:05.813  WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter          : 过滤器:请求地址/client/test
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : uuid:null
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : abc uuid:null
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : authorization :null
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : tom :null
2019-10-30 11:17:05.813 WARN 50223 --- [nio-9011-exec-3] com.xian.cloud.filter.UrlFilter : mike :null

全局设置,和单个服务定制设置 全部生效。

过滤器

spring cloud Zuul包含了对请求的路由和过滤2个功能。路由功能负责将请求转发到具体的微服务上,而过滤器负责对请求的处理过程进行干预,是实现权限校验、服务聚合等功能的基础。

在实际运行时,路由映射和请求转发是由几个不同的过滤器完成的。每一个进入zuul的http请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。

zuul1.0 对流量的路由分发和过滤俩个功能。路由让流量分发到内部的微服务集群上。过滤对请求进行修改或者做个性化处理。实现鉴权、安全、监控、日志等。

运行过程中,流量请求会经过一系列的过滤器最终转发到对应的服务上去。

zuul 路由器主要根绝FilterType类型分为四种类型。一个静态响应StaticResponseFilter

  • pre 在请求被路由之前调用。对应spring boot 工程Filer 中的 doFilter 方法。
  • route 用于路由到原点,使用http 协议调用。可以理解负责转发请求到微服务
  • error 错误处理,在处理请求发生错误时被调用
  • post 用于后路由过滤,在route和error过滤器之后被调用

自定义过滤器

FilterTypeEnum 枚举类

package com.xian.cloud.enums;

import lombok.Getter;

/**
* <Description>
*
* @author xianliru@100tal.com
* @version 1.0
* @createDate 2019/10/29 13:01
*/
@Getter
public enum FilterTypeEnum { PRE("pre","前置过滤"),
ROUTE("route","路由请求时被调用"),
POST("post","后置过滤器"),
ERROR("error","后置错误处理"); private String type; private String desc; FilterTypeEnum(String type,String desc){
this.type = type;
this.desc = desc;
}
}

过滤器代码编写

package com.xian.cloud.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.xian.cloud.enums.FilterTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID; /**
* <Description>
*
* @author xianliru@100tal.com
* @version 1.0
* @createDate 2019/10/29 12:57
*/
@Component
@Slf4j
public class BannedAccessFilter extends ZuulFilter { /**
* 路由器的类型指定
* @return
*/
@Override
public String filterType() {
return FilterTypeEnum.PRE.getType();
} /**
* 执行顺序 数值越小。执行顺序越靠前
* @return
*/
@Override
public int filterOrder() {
return 0;
} /**
* 返回一个boolean值来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。
* @return
*/
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String requestURI = request.getRequestURI();
if(StringUtils.isNotBlank(requestURI) && (requestURI.contains("client") ||
requestURI.contains("server"))){
return true;
}
return false;
} /**
* 核心业务处理
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext context = RequestContext.getCurrentContext();
HttpServletResponse servletResponse = context.getResponse();
String uuid = UUID.randomUUID().toString();
//重写 X-Foo X-ABC值
context.addZuulRequestHeader("X-Foo", uuid);
context.addZuulRequestHeader("X-ABC",uuid);
log.info("X-Foo:{}",uuid);
return null;
}
}

run方法是核心业务处理的方法

postman 请求 http://127.0.0.1:9083/server/server/hello?name=1111 携带之前设置的header参数

服务器打印日志

2019-10-30 14:44:44.841  WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter          : 过滤器:请求地址/server/hello
2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : uuid:a65b2244-e9a5-456d-968f-eaaba45b6f49
2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : abc uuid:null
2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : authorization :null
2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : tom :null
2019-10-30 14:44:44.842 WARN 48882 --- [nio-9012-exec-9] com.xian.cloud.filter.UrlFilter : mike :null
2019-10-30 14:44:44.844 INFO 48882 --- [nio-9012-exec-9] c.x.cloud.controller.DiscoverCotroller : invoked name = 1111 age = 20

可以看到 postman设置的X-Foo 值被 BannedAccessFilter run方法业务覆盖掉了

拦截的请求对参数的修改操作都是在这里。这里单独介绍一下 RequestContext 这个类

官方文档描述

To pass information between filters, Zuul uses a RequestContext. Its data is held in a ThreadLocal specific to
each request. Information about where to route requests, errors and the actual HttpServletRequest and
HttpServletResponse are stored there. The RequestContext extends ConcurrentHashMap, so anything can be
stored in the context. FilterConstants contains the keys that are used by the filters installed by Spring Cloud
Netflix (more on these later).

请求要在过滤器之间传递信息,Zuul使用 RequestContext。其数据按照每个请求的ThreadLocal进行。关于路由请求,错误以及实际HttpServletRequest和HttpServletResponse的路由信息​​。RequestContext扩展ConcurrentHashMap,所以任何东西都可以存储在上下文中。

ThreadLocal保证了请求与请求都是独立的,相互不影响。扩展ConcurrentHashMap 保证内部过滤器并发操作的安全性。

RequestContext 的特殊性。需要单独在创建一个过滤器来展示RequestContext 的使用

需要注意点 都在代码注释上描述出来了。请根据自己的业务场景定制自己的过滤器。

package com.xian.cloud.filter;

import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import com.xian.cloud.enums.FilterTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils; import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* <Description>
*
* @author xianliru@100tal.com
* @version 1.0
* @createDate 2019/10/29 16:07
*/
@Component
@Slf4j
public class UpdateParamsFilter extends ZuulFilter { @Override
public String filterType() {
return FilterTypeEnum.PRE.getType();
} @Override
public int filterOrder() {
return 1;
} @Override
public boolean shouldFilter() {
return true;
} @Override
public Object run() throws ZuulException { // 获取到request
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
// 获取请求参数name
String name = "";
try { // 请求方法
String method = request.getMethod();
log.info(String.format("%s >>> %s", method, request.getRequestURL().toString()));
// 获取请求的输入流
InputStream in = request.getInputStream();
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
// 如果body为空初始化为空json
if (StringUtils.isBlank(body)) {
body = "{}";
}
log.info("body" + body);
// 转化成json
JSONObject json = JSONObject.parseObject(body);
// 关键步骤,一定要get一下,下面才能取到值requestQueryParams
if ("GET".equals(method)) {
request.getParameterMap();
Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
if (requestQueryParams == null) {
requestQueryParams = new HashMap<>();
}
//TODO 写业务代码
List<String> arrayList = new ArrayList<>();
arrayList.add("hello mike");
//requestQueryParams.put("mike",arrayList);
ctx.setRequestQueryParams(requestQueryParams);
}
//post和put需重写HttpServletRequestWrapper
if ("POST".equals(method) || "PUT".equals(method)) {
//TODO 在这里修改或者添加内容
json.put("tom","hello tom");
String newBody = json.toString();
final byte[] reqBodyBytes = newBody.getBytes();
// 重写上下文的HttpServletRequestWrapper
ctx.setRequest(new HttpServletRequestWrapper(request) {
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(reqBodyBytes);
}
@Override
public int getContentLength() {
return reqBodyBytes.length;
}
@Override
public long getContentLengthLong() {
return reqBodyBytes.length;
}
});
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

本章过滤器内容讲述完毕。下个章节 我们来介绍 ,基于网关zuul服务的 动态路由 功能。

摘自参考 spring cloud 官方文档

示例代码地址

服务器nacos 地址 http://47.99.209.72:8848/nacos

往期地址 spring cloud alibaba 地址

spring cloud alibaba 简介

Spring Cloud Alibaba (nacos 注册中心搭建)

Spring Cloud Alibaba 使用nacos 注册中心

Spring Cloud Alibaba nacos 配置中心使用

spring cloud 网关服务

Spring Cloud zuul网关服务 一

如何喜欢可以关注分享本公众号。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。转载请附带公众号二维码

Spring Cloud 网关服务 zuul 二的更多相关文章

  1. Spring Cloud 网关服务 zuul 三 动态路由

    zuul动态路由 网关服务是流量的唯一入口.不能随便停服务.所以动态路由就显得尤为必要. 数据库动态路由基于事件刷新机制热修改zuul的路由属性. DiscoveryClientRouteLocato ...

  2. spring cloud 网关服务

    微服务 网关服务 网关服务是微服务体系里面重要的一环. 微服务体系内,各个服务之间都会有通用的功能比如说:鉴权.安全.监控.日志.服务调度转发.这些都是可以单独抽象出来做一个服务来处理.所以微服务网关 ...

  3. spring cloud微服务实践二

    在上一篇,我们已经搭建了spring cloud微服务中的注册中心.但只有一个注册中心还远远不够. 接下来我们就来尝试提供服务. 注:这一个系列的开发环境版本为 java1.8, spring boo ...

  4. spring cloud网关通过Zuul RateLimit 限流配置

    目录 引入依赖 配置信息 RateLimit源码简单分析 RateLimit详细的配置信息解读 在平常项目中为了防止一些没有token访问的API被大量无限的调用,需要对一些服务进行API限流.就好比 ...

  5. Spring Cloud 微服务二:API网关spring cloud zuul

    前言:本章将继续上一章Spring Cloud微服务,本章主要内容是API 网关,相关代码将延续上一章,如需了解请参考:Spring Cloud 微服务一:Consul注册中心 Spring clou ...

  6. spring cloud 学习(6) - zuul 微服务网关

    微服务架构体系中,通常一个业务系统会有很多的微服务,比如:OrderService.ProductService.UserService...,为了让调用更简单,一般会在这些服务前端再封装一层,类似下 ...

  7. Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

    导读 我们知道在基于Spring Cloud的微服务体系中,各个微服务除了在内部提供服务外,有些服务接口还需要直接提供给客户端,如Andirod.IOS.H5等等. 而一个很尴尬的境地是,如果直接将提 ...

  8. Spring Cloud 微服务三: API网关Spring cloud gateway

    前言:前面介绍了一款API网关组件zuul,不过发现spring cloud自己开发了一个新网关gateway,貌似要取代zuul,spring官网上也已经没有zuul的组件了(虽然在仓库中可以更新到 ...

  9. Spring Cloud微服务笔记(二)Spring Cloud 简介

    Spring Cloud 简介 Spring Cloud的设计理念是Integrate Everything,即充分利用现有的开源组件, 在它们之上设计一套统一的规范/接口使它们能够接入Spring ...

随机推荐

  1. 一步步构建.NET Core Web应用程序---仓储层,业务层的实现

    前言 上一篇文章介绍了整个项目的结构,接下来向大家介绍一下 我的 仓储及业务层具体的实现思路,如果有更好的实现方式,希望大家及时指出!!! 构建过程 一,数据访问 首先在 DataProvider 中 ...

  2. Github 入门1 (下载git , 连接本地库与github仓库)

    /* 本篇建立在以注册GitHub账号的前提下*/ (1)  下载 git  https://www.git-scm.com // win10 可以直接红色箭头标识的 Download 2.22.0 ...

  3. Spring boot 官网学习笔记 - Configuration Class(@import)

    推荐使用 Java-based configuration ,也可以使用xml we generally recommend that your primary source be a single ...

  4. 读《深入理解Elasticsearch》点滴-查询评分

    计算文档得分的因子: 文档权重(document boost):索引期赋予某个文档的权重值 字段权重(field boost):查询期赋予某个文档的权重值 协调因子(coord):基于文档中词项个数的 ...

  5. linux下搭建nginx+mysql+apache

    对于开发人员来说,进行Web开发时可以用Apache进行网站测试,然而当一个Web程序进行发布时,Apache中并发性能差就显得很突出,这时配置一台Nginx服务器显得尤为重要. 以下是配置Nginx ...

  6. css 添加手状样式,鼠标移上去变小手

    cursor:pointer, 简单实用. 前端工作一年多,竟然没有博客.说出来别人都要笑话,这是一个新的开始.

  7. InnoDB体系结构

    1.前言 整理了下InnoDB体系结构,方便以后更简单的理解 2.思维导图 参考: https://www.cnblogs.com/tangshiguang/p/6741035.html https: ...

  8. vue多级复杂列表展开/折叠,全选/分组全选实现

    首先,来看下效果图 在线体验地址:https://hxkj.vip/demo/multipleList/.温馨提示,打开之后按F12,使用手机模式食用,口味更佳! 可以看出,这个列表有三种展现形式: ...

  9. 从0开始学FreeRTOS-1

    我们知道,(单核)单片机某一时刻只能干一件事,会造成单片机资源的浪费,而且还有可能响应不够及时,所以,在比较庞大的程序或者是要求实时性比较高的情况下,我们可以移植操作系统.因为这种情况下操作系统比裸机 ...

  10. Kubernetes+Docker+Istio 容器云实践

    随着社会的进步与技术的发展,人们对资源的高效利用有了更为迫切的需求.近年来,互联网.移动互联网的高速发展与成熟,大应用的微服务化也引起了企业的热情关注,而基于Kubernetes+Docker的容器云 ...