Spring Cloud 入门——4.2 Zuul 分布式路由实现文件上传 以及 异常处理

24 篇文章 0 订阅
22 篇文章 3 订阅

代码信息

本篇文章涉及代码版本

组件版本
Spring Boot2.0.8.RELEASE
Spring CloudFinchley.SR1

本篇文章涉及应用

应用说明
base-eureka服务发现
base-zuul-upload配置上传限制的路由网关
base-producer-upload提供文件上传的应用

上一篇使用zuul实现了路由网关,既然zuul可以实现统一的网关控制那么使用zuul同样可以尝试文件大小控制

创建一个接收文件上传的服务

构建maven依赖

需要添加spring的web的相关支持。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

参数配置application.yml

此处为了测试zuul的文件拦截是否生效将client的文件大小上调至50MB

spring:
  application:
    name: base-producer-upload
  servlet:
    multipart:
      enabled: true
      max-file-size: 50MB
server:
  port: 8105

eureka:
  client:
    service-url:
      # 服务发现项目的地址
      defaultZone: http://localhost:8000/eureka/
logging:
  file: ${spring.application.name}.log
           

代码编写

上传代码

@RestController
public class FileUploadController {

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String test()
            throws IOException {
        return "test";
    }

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String handleFileUpload(@RequestParam(value = "file") MultipartFile file) 
            throws IOException {
        byte[] bytes = file.getBytes();
        File fileToSave = new File(file.getOriginalFilename());
        FileCopyUtils.copy(bytes, fileToSave);
        return fileToSave.getAbsolutePath();
    }
}

zuul的配置

在zuul中将文件上传大小限制为10MB

spring:
  application:
    name: base-zuul-upload
  servlet:
    multipart:
      enabled: true
      max-file-size: 10Mb
server:
  port: 8301
eureka:
  client:
    service-url: 
      defaultZone: http://localhost:8000/eureka/
logging:
  file: ${spring.application.name}.log
zuul:
  routes: 
    consumer:
      path: /client/**
      serviceId: base-producer-upload

consumer:
  ribbon:
    listOfServers: http://localhost:8105/

测试

为了方便测试本地编写了一个上传页面

[外链图片转存失败(img-sRzh07is-1563624088277)(AC09175FEC8F4C38A02A8CA34C86208D)]

首先我们测试一个小图片

[外链图片转存失败(img-TTbtZGKo-1563624088278)(46E2A5A87E9A4F5D9B92FCAD94DA5054)]
可以看到成功上传了。

异常拦截处理

因为使用了form表单点击后页面会进行跳转,无法看到错误内容。所以我编写了个错误处理类进行处理。

/**
 * @author daify
 * @date 2019-07-08
 */
@ControllerAdvice
@Slf4j
public class ZuulRestControllerAdvice {

    /**
     * 全局异常处理,反正异常返回统一格式的map
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public String exceptionHandler(Exception ex){
        log.error("------------------------------------");
        log.error("发生了异常");
        log.error(ex.getMessage());
        return "error";
    }
}

然后我们上传一个超过10MB但是小于50MB的内容。可以看到控制台打印了错误内容。

2019-07-08 22:15:44.580 ERROR 6592 --- [nio-8301-exec-2] d.z.c.ZuulRestControllerAdvice           : ------------------------------------
2019-07-08 22:15:44.580 ERROR 6592 --- [nio-8301-exec-2] d.z.c.ZuulRestControllerAdvice           : 发生了异常
2019-07-08 22:15:44.580 ERROR 6592 --- [nio-8301-exec-2] d.z.c.ZuulRestControllerAdvice           : Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (18084623) exceeds the configured maximum (10485760)

首先可以看到我发起了一次申请却出现了错误的日志

zuul的异常处理逻辑

上面最开始我是尝试使用上一篇中使用的ZuulFilter进行错误处理。但是实际上发现并没有起到任何作用,然后我又仔细看了ZuulFilter的处理过程。

这是ZuulFilter异常处理过程。
[外链图片转存失败(img-HfWcIAxt-1563624088278)(6D1E9AAEDEE74E958A633260EB687744)]

从上面可以看出来ZuulFilter其实主要处理的是pre、routing、post阶段时候发生的异常。而文件上传的限制是zuul应用作为一个springboot项目自身的限制。这个时候使用ZuulFilter自然无法拦截。

新建一个ZuulFilter的异常处理

@Slf4j
@Component
public class ErrorFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "error";
    }

    @Override
    public int filterOrder() {
        return -1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        try {
            RequestContext ctx = RequestContext.getCurrentContext();
            Throwable throwable = ctx.getThrowable();
            if (throwable != null && throwable instanceof ZuulException) {
                log.error("Zuul failure --------------------------------- ");
                ZuulException zuulException = (ZuulException)throwable;
                log.error("Zuul failure detected: " + zuulException.getMessage(), zuulException);

                ctx.remove("error.status_code");
                ctx.setResponseBody("Overriding Zuul Exception Body");
                ctx.getResponse().setContentType("application/json");
                ctx.setResponseStatusCode(500);
            }
        } catch (Exception ex) {
            log.error("Exception filtering in custom error filter", ex);
            ReflectionUtils.rethrowRuntimeException(ex);
        }
        return null;
    }
}


在之前这个异常处理已经在项目中存在,但是在文件大小超过上限的错误这个过滤器并没有发挥作用。之前在base-producer-upload编写了一个测试方法test,我们之前的调用是没有问题的。现在我们关闭掉base-producer-upload项目,然后发起请求可以看到控制台打印下面内容。

2019-07-08 22:54:40.282 ERROR 21476 --- [nio-8301-exec-1] dailearn.zuul.filter.ErrorFilter         : Zuul failure --------------------------------- 
2019-07-08 22:54:40.285 ERROR 21476 --- [nio-8301-exec-1] dailearn.zuul.filter.ErrorFilter         : Zuul failure detected: Filter threw Exception

com.netflix.zuul.exception.ZuulException: Filter threw Exception
	at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227) ~[zuul-core-1.3.1.jar:1.3.1]
	at com.netflix.zuul.FilterProcessor.runFilters(FilterProcessor.java:157) ~[zuul-core-1.3.1.jar:1.3.1]
	at com.netflix.zuul.FilterProcessor.route(FilterProcessor.java:118) ~[zuul-core-1.3.1.jar:1.3.1]
	at com.netflix.zuul.ZuulRunner.route(ZuulRunner.java:96) ~[zuul-core-1.3.1.jar:1.3.1]
	at com.netflix.zuul.http.ZuulServlet.route(ZuulServlet.java:116) ~[zuul-core-1.3.1.jar:1.3.1]
	at com.netflix.zuul.http.ZuulServlet.service(ZuulServlet.java:81) ~[zuul-core-1.3.1.jar:1.3.1]
	at org.springframework.web.servlet.mvc.ServletWrappingController.handleRequestInternal(ServletWrappingController.java:165) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at org.springframework.cloud.netflix.zuul.web.ZuulController.handleRequest(ZuulController.java:44) [spring-cloud-netflix-zuul-2.0.1.RELEASE.jar:2.0.1.RELEASE]
	at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:52) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:873) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.37.jar:8.5.37]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858) [spring-webmvc-5.0.12.RELEASE.jar:5.0.12.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) [tomcat-embed-core-8.5.37.jar:8.5.37]
	......

这个时候才是ZuulFilter发挥作用的时候。

总结

可以这么简单的理解

  • zuul项目本身请求导致的错误可以使用springboot的异常处理逻辑。
  • zuul远程调用时发生的错误可以使用ZuulFilter的error来进行处理。

本篇文章并未贴出所有代码,涉及的源码下载地址:https://gitee.com/daifylearn/cloud-learn

ps.上述的所有项目都是可以成功运行的。但是在后期为了实现每个应用端口尽量不冲突会有些许调整,而后续某次作死调整结构和名称可能会导致部分项目无法运行o(╯□╰)o,如果发现请留言我进行修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大·风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值