ZUUL网关 路径映射 网关降级 过滤器

ZUUL网关

网关==转发,以后访问服务的时候,不需要每次都访问每个服务的地址,只需要访问网关就可以

主要是做请求拆分 , 消息合并 , 协议转换

注意:版本E以及之前,可以直接访问http:localhost://端口号/routes or filter

从版本H开始在前面就要访问 http:localhost://端口号/actuator/routes or filter

pom.xml

<span style="background-color:#f8f8f8"><span style="color:#333333">​
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.cloud<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-cloud-starter-netflix-zuul<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
​
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#aa5500"><!--访问 eureka 的页面的时候需要密码--></span>
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.boot<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-boot-starter-security<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#aa5500"><!--通过 eureka 来拉取服务列表--></span>
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.cloud<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-cloud-starter-netflix-eureka-client<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
​
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span></span></span>

application.yml

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">server</span><span style="color:#555555">:</span>
<span style="color:#221199">  port</span><span style="color:#555555">: </span><span style="color:#116644">16500</span>
<span style="color:#221199">eureka</span><span style="color:#555555">: </span><span style="color:#aa5500">#注册中心的地址,用于获取服务列表</span>
<span style="color:#221199">  client</span><span style="color:#555555">:</span>
<span style="color:#221199">    service-url</span><span style="color:#555555">:</span>
<span style="color:#221199">      defaultZone</span><span style="color:#555555">: </span>http<span style="color:#555555">:</span>//zhangsan<span style="color:#555555">:</span>abc@localhost<span style="color:#555555">:</span>10000/eureka <span style="color:#aa5500">#curl风格</span>
​
<span style="color:#221199">spring</span><span style="color:#555555">:</span>
<span style="color:#221199">  application</span><span style="color:#555555">:</span>
<span style="color:#221199">    name</span><span style="color:#555555">: </span>22apigateway-zuul
<span style="color:#221199">  security</span><span style="color:#555555">:</span>
<span style="color:#221199">    user</span><span style="color:#555555">:</span>
<span style="color:#221199">      password</span><span style="color:#555555">: </span>xiaomei
<span style="color:#221199">      name</span><span style="color:#555555">: </span>laowang <span style="color:#aa5500">#默认是user</span>
<span style="color:#221199">management</span><span style="color:#555555">:</span>
<span style="color:#221199">  endpoints</span><span style="color:#555555">:</span>
<span style="color:#221199">    web</span><span style="color:#555555">:</span>
<span style="color:#221199">      exposure</span><span style="color:#555555">:</span>
<span style="color:#221199">        include</span><span style="color:#555555">: </span><span style="color:#aa1111">'*'</span>  <span style="color:#aa5500">#允许访问所有管理地址,不然无法通过网页查看路由的列表页/actuator/routes,但是不影响路由功能更</span></span></span>

注解

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@EnableZuulProxy</span></span></span>

映射路径

自定义映射路径

因为我们注册中心设置的请求名字可能会比较复杂,我们可以通过yml文件来把这个地址映射到你想换的地址,如果多个域名需要修改,在下一行这样写就可以

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    13orderconsumer-openfeign-hytrix</span> <span style="color:#555555">: </span>/jinwandalaohu/**  <span style="color:#aa5500">#要想访问13orderconsumer-openfeign-hytrix路径需要通过jinwandalaohu来访问</span></span></span>

映射了请求地址以后,我们发现原本的域名也可以访问,如果不想之前的地址访问,我们就需要在yml文件里面添加忽略服务的列表

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    13orderconsumer-openfeign-hytrix</span> <span style="color:#555555">: </span>/jinwandalaohu/**  <span style="color:#aa5500">#要想访问13orderconsumer-openfeign-hytrix路径需要通过jinwandalaohu来访问</span>
<span style="color:#221199">    itemprovider-eureka-hystrix</span> <span style="color:#555555">: </span>/laohubanichile/**
<span style="color:#221199">  ignored-services</span><span style="color:#555555">:</span>
    13orderconsumer-openfeign-hytrix , itemprovider-eureka-hystrix  <span style="color:#aa5500">#添加忽略的服务列表,多个以,分开,如果是忽略所有则写'*'</span></span></span>

映射其他服务的集群

在实际开发中,我们的服务节点都是集群,当一个服务集群没有在eureka上面注册的时候,我们需要单独配置

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    aaaaa</span><span style="color:#555555">: </span><span style="color:#aa5500">#随便写,但是在配置文件里面不能重复</span>
<span style="color:#221199">      path</span><span style="color:#555555">: </span>/abcdefg/** <span style="color:#aa5500">#映射后的地址</span>
<span style="color:#221199">      serviceId</span><span style="color:#555555">: </span>05consumer-eureka <span style="color:#aa5500">#要给哪个服务设置路由地址</span>
<span style="color:#221199">    bbbb</span><span style="color:#555555">:</span>
<span style="color:#221199">      path</span><span style="color:#555555">: </span>/def/**
<span style="color:#221199">      serviceId</span><span style="color:#555555">: </span>04provider-eureka</span></span>

同一前缀

像controller一样,在zuul里面我们也可以给地址同一前缀,只需要在yml文件里设置就好了

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">    prefix</span><span style="color:#555555">: </span>/suibian</span></span>

表达式映射(灰度发布)

当我们升级服务的时候版本不同,对应的接口可能也不同 ,(灰度发布==>会同时存在两个不同的版本服务)为了方便访问,我们的网关里面提供了一个表达式方式来方便我们进行操作

<span style="background-color:#f8f8f8"><span style="color:#333333"> <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 设置服务的映射方式,当我们的服务的名字是  name-vx 的方式进行命名的时候,访问地址会被映射为 vx/name</span>
     <span style="color:#aa5500">* 一般我们会通过这个方式来进行版本区分</span>
     <span style="color:#aa5500">* 比如一个服务叫 gouwuche-v1,那么它的路径就是 v1/gouwuche</span>
     <span style="color:#aa5500">* 当我们的这个服务升级后我们只需要将名字改成 gouwuche-v2 那么客户端就可以通过不同的版本前缀来访问不同版本的服务</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Bean</span>
    <span style="color:#770088">public</span> <span style="color:#000000">PatternServiceRouteMapper</span> <span style="color:#0000ff">serviceRouteMapper</span>() {
      <span style="color:#aa5500">//其中<name> <version>是一个别名,是对应表达式内容的别名 ,实际上 name 代表的是^. 也就是任意内容 <version>代表是 v.代表以 v 开始的内容,所以下面的表达式代表是 name-vx</span>
        <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">PatternServiceRouteMapper</span>(
                <span style="color:#aa1111">"(?<name>^.+)-(?<version>v.+$)"</span>,
                <span style="color:#aa1111">"${version}/${name}"</span>);
    }</span></span>

网关降级

当网关出现异常,也可以实施fallback降级操作,实现FallbackProvider接口,根据实际业务需求,重写里面的方法

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">MyFallbackProvider</span> <span style="color:#770088">implements</span> <span style="color:#000000">FallbackProvider</span> {
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 当前fallback是给哪个服务用的,如果是所有的类,则返回'*'</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getRoute</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"*"</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">*</span>
     <span style="color:#aa5500">* @param route 具体出现问题的服务</span>
     <span style="color:#aa5500">* @param cause 出现问题的原因</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#000000">ClientHttpResponse</span> <span style="color:#000000">fallbackResponse</span>(<span style="color:#008855">String</span> <span style="color:#000000">route</span>, <span style="color:#000000">Throwable</span> <span style="color:#000000">cause</span>) {
        <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">ClientHttpResponse</span>() {
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">HttpStatus</span> <span style="color:#000000">getStatusCode</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#000000">HttpStatus</span>.<span style="color:#000000">OK</span>;<span style="color:#aa5500">//根据自己业务的实际情况返回对应的值</span>
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">getRawStatusCode</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#116644">200</span>;<span style="color:#aa5500">//状态码</span>
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getStatusText</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#aa1111">"根据情况返回"</span>;
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">close</span>() {
​
            }
​
            <span style="color:#aa5500">/**</span>
             <span style="color:#aa5500">*</span>
             <span style="color:#aa5500">* @return  我们要返回的内容,通过io流返回</span>
             <span style="color:#aa5500">* @throws IOException</span>
             <span style="color:#aa5500">*/</span>
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">InputStream</span> <span style="color:#000000">getBody</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">ByteArrayInputStream</span>(<span style="color:#aa1111">"啥啊也不是"</span>.<span style="color:#000000">getBytes</span>(<span style="color:#000000">StandardCharsets</span>.<span style="color:#000000">UTF_8</span>));
            }
​
            <span style="color:#aa5500">/**</span>
             <span style="color:#aa5500">* 响应头</span>
             <span style="color:#aa5500">* @return</span>
             <span style="color:#aa5500">*/</span>
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">HttpHeaders</span> <span style="color:#000000">getHeaders</span>() {
                <span style="color:#000000">HttpHeaders</span> <span style="color:#000000">httpHeaders</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">HttpHeaders</span>();
                <span style="color:#000000">httpHeaders</span>.<span style="color:#000000">add</span>(<span style="color:#aa1111">"Content-Type"</span>,<span style="color:#aa1111">"text/html;charset=utf-8"</span>);
                <span style="color:#770088">return</span> <span style="color:#000000">httpHeaders</span>;
            }
        };
    }
}</span></span>

error地址转换

当我们的服务出现异常的时候,spring给我们提供了一个错误地址,我们可以将这个地址映射成我们自己的,返回我们给用户看到的内容

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.Sun Nov 07 14:29:38 CST 2021
There was an unexpected error (type=Not Found, status=404).
 

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@RestController</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ErrorController</span> <span style="color:#770088">implements</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">boot</span>.<span style="color:#000000">web</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">error</span>.<span style="color:#000000">ErrorController</span> {
    <span style="color:#555555">@PostMapping</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"/error"</span>,<span style="color:#000000">produces</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"text/html;charset=utf-8"</span>)
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">processError</span>(){
        <span style="color:#770088">return</span> <span style="color:#aa1111">"你的电脑出现重大问题,撒冷给我送来"</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">*我们要替代哪个地址,返回值替对应的地址会映射成我们自己的,而不是spring自带的</span>
     <span style="color:#aa5500">* 在2.3.0版本及之前,要实现这个方法,2.3.0之后可以不实现这个方法,系统自动会映射成我们的</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getErrorPath</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"/error"</span>;<span style="color:#aa5500">//替代这个地址</span>
    }
}</span></span>


过滤器Filter

网关给我们提供了filter过滤器让我们来进行批量操作,如: 获取请求,中断请求,返回结果等..

我们只要实现ZuuFilter接口,重写里面的方法就可以实现过滤器功能

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">MyPreFilter</span> <span style="color:#770088">extends</span> <span style="color:#000000">ZuulFilter</span> {
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 当前过滤器的类型</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">filterType</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">FilterConstants</span>.<span style="color:#000000">PRE_TYPE</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 过滤器的顺序,在相同type的情况下下,数字越小,优先级越高</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">filterOrder</span>() {
        <span style="color:#770088">return</span> <span style="color:#116644">0</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 当前过滤器是否开启,</span>
     <span style="color:#aa5500">* 此处根据实际的业务需求来决定是否开启</span>
     <span style="color:#aa5500">* false不开启</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">shouldFilter</span>() {
        <span style="color:#770088">return</span> <span style="color:#221199">false</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* 如果过滤器开启了,则会执行此操作</span>
     <span style="color:#aa5500">* @return 无意义,因为不是返回用户的</span>
     <span style="color:#aa5500">* @throws ZuulException</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">Object</span> <span style="color:#000000">run</span>() <span style="color:#770088">throws</span> <span style="color:#000000">ZuulException</span> {
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
}</span></span>

通过看源码我们发现,zuul给我们提供了前置过滤器PRE_TYPE ,后端过滤器POST_TYPE,路由过滤器ROUTE_TYPE,错误过滤器ERROR_TYPE ,我们根据也无需求来选择我们需要的过滤器,在相同的type情况下,filterOrder()方法返回的数字越小,优先级越高.

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//TODO 如果过滤器需要强制转发服务,那这个过滤器的 order 必须大于等于 5,因为 zuul 内部有其他的过滤器会进行封装操作,我强制更改后会导致它有些数据无法获取</span></span></span>

过滤器还给我们提供了一些封装好的方法:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">RequestContext</span> <span style="color:#000000">requestContext</span> <span style="color:#981a1a">=</span> <span style="color:#000000">RequestContext</span>.<span style="color:#000000">getCurrentContext</span>();
<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span> <span style="color:#981a1a">=</span> <span style="color:#000000">requestContext</span>.<span style="color:#000000">getRequest</span>();<span style="color:#aa5500">//获取请求</span>
<span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span> <span style="color:#981a1a">=</span> <span style="color:#000000">requestContext</span>.<span style="color:#000000">getResponse</span>();<span style="color:#aa5500">//获取响应</span>
<span style="color:#008855">String</span> <span style="color:#000000">requestURI</span> <span style="color:#981a1a">=</span> <span style="color:#000000">request</span>.<span style="color:#000000">getRequestURI</span>();<span style="color:#aa5500">//获取请求的URI</span>
<span style="color:#000000">System</span>.<span style="color:#000000">err</span>.<span style="color:#000000">println</span>(<span style="color:#000000">requestURI</span>);
<span style="color:#aa5500">//前置通知可以中断请求的运行</span>
<span style="color:#aa5500">//requestContext.setSendZuulResponse(false);//拦截请求</span>
<span style="color:#aa5500">//拦截之后设置返回结果</span>
<span style="color:#000000">response</span>.<span style="color:#000000">setContentType</span>(<span style="color:#aa1111">"text/html;charset=utf-8"</span>);
<span style="color:#000000">requestContext</span>.<span style="color:#000000">put</span>(<span style="color:#aa1111">"suibian"</span>, <span style="color:#aa1111">"拦截后返回的内容"</span>);</span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">//前置通知可以中断请求的运行</span>
<span style="color:#aa5500">//requestContext.setSendZuulResponse(false);//拦截请求</span></span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">   <span style="color:#000000">requestContext</span>.<span style="color:#000000">put</span>(<span style="color:#000000">FilterConstants</span>.<span style="color:#000000">SERVICE_ID_KEY</span>, <span style="color:#aa1111">"12itemprovider-eureka-hystrix"</span>);<span style="color:#aa5500">//将当前的请求强制转发到哪个服务</span>
<span style="color:#aa5500">//   requestContext.put(FilterConstants.REQUEST_URI_KEY, "/items/item/test1");//强制转发到上面服务中的哪个地址</span></span></span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值