SpringCloud入門(九): Zuul 上傳&回退&異常處理&跨域

Zuul的上傳

1、構建一個上傳類

import org.springframework.web.bind.annotation.PostMapping;  import org.springframework.web.bind.annotation.RequestMapping;  import org.springframework.web.bind.annotation.RequestParam;  import org.springframework.web.bind.annotation.RestController;  import org.springframework.web.multipart.MultipartFile;    import java.io.*;    @RestController  @RequestMapping("/file")  public class FileUploadController {        @PostMapping(value = "/upload", consumes = "multipart/form-data")      public Object upload(@RequestParam("file") MultipartFile file) throws IOException {          File temp = new File("D:/" + file.getOriginalFilename());          if(!temp.getParentFile().exists()){              temp.getParentFile().mkdir();          }          try {              file.transferTo(temp); //保存文件              return Boolean.TRUE;          } catch (IllegalStateException e) {              e.printStackTrace();              return Boolean.FALSE;          } catch (IOException e) {              e.printStackTrace();              return Boolean.FALSE;          }      }  }

2、配置屬性文件

zuul默認文件上傳的時候,會走Spring DispatcherServlet,這個時候會對文件大小進行判斷,默認為10M;如果要傳大文件需要對文件大小進行設置。

zuul.ignored-services=*  zuul.routes.use-routing.serviceId=ms-provider-order  zuul.routes.use-routing.path=/order-service/**  zuul.routes.use-routing.sensitiveHeaders=    spring.servlet.multipart.max-file-size=4000MB  spring.servlet.multipart.max-request-size=4000MB

通過/zuul來訪問,可以繞過DispatcherServlet轉為zuulServlet,在上傳大文件的時候不需要設置文件大小,但是需要設置hystrix和ribbon的超時時間。

zuul.ignored-services=*  zuul.routes.use-routing.serviceId=ms-provider-order  zuul.routes.use-routing.path=/order-service/**  zuul.routes.use-routing.sensitiveHeaders=    hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=600000  ribbon.ConnectTimeout=100000  ribbon.ReadTimeout=100000

3、通過PostMan測試

zuul的回退

1、自定義一個回退類

import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;  import org.springframework.http.HttpHeaders;  import org.springframework.http.HttpStatus;  import org.springframework.http.MediaType;  import org.springframework.http.client.ClientHttpResponse;    import java.io.ByteArrayInputStream;  import java.io.IOException;  import java.io.InputStream;    public class CustomZuulFallBack implements FallbackProvider {      @Override      public String getRoute() {          return "*"; //*表示為所有微服務提供回退          //return "ms-provider-order"  //指定某個微服務回退      }        @Override      public ClientHttpResponse fallbackResponse(String route, Throwable cause) {          return new ClientHttpResponse() {              @Override              public HttpStatus getStatusCode() throws IOException {                  return HttpStatus.OK;              }                @Override              public int getRawStatusCode() throws IOException {                  return HttpStatus.OK.value();              }                @Override              public String getStatusText() throws IOException {                  return HttpStatus.OK.getReasonPhrase();              }                @Override              public void close() {                }                @Override              public InputStream getBody() throws IOException {                  return new ByteArrayInputStream("後端服務不可用".getBytes());              }                @Override              public HttpHeaders getHeaders() {                  HttpHeaders headers = new HttpHeaders();                  //和body中的內容編碼一致,否則容易亂碼                  headers.setContentType(MediaType.APPLICATION_JSON_UTF8);                  return headers;              }          };      }  }

zuul的回退只支援宕機回退(服務掛了)和超時回退(服務請求超時)兩種;

如果服務自己拋出的異常(404,500等),zuul的回退監控不到;原因就在於RibbonRoutingFilter的攔截器,在攔截器run中的forward方法,只爭對了HystrixRuntimeException的攔截,500等異常會直接由SpringBoot的BasicErrorController接管拋出到頁面;

protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {      Map<String, Object> info = this.helper.debug(context.getMethod(),              context.getUri(), context.getHeaders(), context.getParams(),              context.getRequestEntity());        RibbonCommand command = this.ribbonCommandFactory.create(context);      try {          ClientHttpResponse response = command.execute();          this.helper.appendDebug(info, response.getRawStatusCode(), response.getHeaders());          return response;      }      catch (HystrixRuntimeException ex) {          return handleException(info, ex);      }  }

zuul的全局異常處理

1、自定義一個異常處理類

import com.alibaba.fastjson.JSON;  import com.netflix.zuul.context.RequestContext;  import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;  import org.springframework.stereotype.Component;  import org.springframework.util.ReflectionUtils;    import javax.servlet.http.HttpServletResponse;  import java.util.HashMap;  import java.util.Map;    @Component  public class CustomErrorFilter extends SendErrorFilter {        @Override      public Object run() {          try {              RequestContext ctx = RequestContext.getCurrentContext();              ExceptionHolder exception = findZuulException(ctx.getThrowable());              //HttpServletRequest request = ctx.getRequest();                HttpServletResponse response = ctx.getResponse();              response.setContentType("text/html; charset=UTF-8");              response.setCharacterEncoding("UTF-8");                Map<String,Object> errorMap = new HashMap<>();              errorMap.put("code","203");              errorMap.put("errMsg",exception.getThrowable().getCause().getMessage());                response.getWriter().write(JSON.toJSONString(errorMap));          }          catch (Exception ex) {              ReflectionUtils.rethrowRuntimeException(ex);          }          return null;      }  }

2、禁用系統自帶的異常處理類

zuul.SendErrorFilter.error.disable=true

zuul的跨域問題

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;    @Configuration  public class CorsConfig {        @Bean      public CorsFilter corsFilter() {            final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();          final CorsConfiguration config = new CorsConfiguration();          config.setAllowCredentials(true); // 允許cookies跨域          config.addAllowedOrigin("*");// #允許向該伺服器提交請求的URI,*表示全部允許,在SpringMVC中,如果設成*,會自動轉成當前請求頭中的Origin          config.addAllowedHeader("*");// #允許訪問的頭資訊,*表示全部          config.setMaxAge(18000L);// 預檢請求的快取時間(秒),即在這個時間段里,對於相同的跨域請求不會再預檢了          config.addAllowedMethod("*");// 允許提交請求的方法,*表示全部允許          source.registerCorsConfiguration("/**", config);          return new CorsFilter(source);      }  }