18.Spring-Cloud-Zuul之文件上传和容错与回退
对于通过API网关调用文件上传服务来说,文件(1M以内)无须任何处理,即看正常上传。对于大文件(10M以上)上传。需要在上传路径上添加/zuul前缀。也可使用zuul.servlet-path自定义前缀。
文件上传演示
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>2.spring-cloud-service-provide</groupId> <artifactId>service-provide</artifactId> <packaging>jar</packaging> <version>0.0.1-SNAPSHOT</version> <name>spring-cloud Maven Webapp</name> <url>http://maven.apache.org</url> <!--springboot采用1.5.x 对应springcloud版本为 Dalston --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.RELEASE</version> <relativePath /> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.RELEASE</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- freemarker --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.15</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 这样变成可执行的jar --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
启动类
package com.niugang; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.annotation.ComponentScan; /** * 文件上传 * @author niugang * */ @SpringBootApplication @EnableDiscoveryClient @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
配置文件
#指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问 spring.application.name=service-fileupload-v1 server.port=8778 #注册中心地址 eureka.client.serviceUrl.defaultZone=http://testhost:8000/eureka/,http://testhost2:8001/eureka/ #把客户端的检测检测交给actuator来完成 eureka.client.healthcheck.enabled=true #配置freemaker #默认加载类路径下 templates文件夹下的页面 #spring.freemarker.template-loader-path= spring.freemarker.cache=false spring.freemarker.charset=UTF-8 spring.freemarker.check-template-location=true spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=true spring.freemarker.expose-session-attributes=true spring.freemarker.request-context-attribute=request spring.freemarker.suffix=.html #配置文件上传大小 spring.http.multipart.max-file-size=20Mb spring.http.multipart.max-request-size=100Mb
controller
package com.niugang.controller; import java.io.File; import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; @Controller public class UploadController { private final Logger logger = LoggerFactory.getLogger(UploadController.class); @RequestMapping(value = "/index") public String index() { return "index"; } /** * * @return * @throws IOException */ @RequestMapping(value = "/upload", method = RequestMethod.POST) @ResponseBody public String upload(MultipartFile file) throws IOException { byte[] bytes = file.getBytes(); //这样默认上传文件就放在当前 项目路径下 File name = new File(file.getOriginalFilename()); FileCopyUtils.copy(bytes, name); return name.getAbsolutePath(); } }
页面:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>文件上传</title> </head> <body> <h4>spring cloud zuul 文件上传</h4> <form method="POST" action="upload" enctype="multipart/form-data"> <input type="file" name="file" /><br /> <br /> <input type="submit" value="提交" /> </form> </body> </html>
1.输入:http://localhost:8777/v1/service-fileupload/index启动注册中心,文件上传微服务,api网关。
上传小于1M的;
文件上传成功
上传大于1M的:
文件上传失败
修改文件上传路径
大文件上传成功
zuul容错回退
在没有添加zull容错回退是,经常可能因为请求转发报超时。
1.其中如果不添加回退可以调大请求转发超时时间如下:
#API网关路由转发请求hystrixCommand执行超时时间,默认为1000 即1s
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000
2.添加回退
为zuul添加回退,需要实现ZuulFallbackProvider接口。在实现类中,指定为那个微服务提供回退,并提供一个ClientHttpResponse作为回退响应。
package com.niugang.fallback; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; /** * * @author zuul降级处理 *当路由发生故障时提供回退。 */ @Component public class HellServiceFallback implements ZuulFallbackProvider { @Override public String getRoute() { //表明为那个微服务提供回退 return "feign-consumer-v1"; } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpHeaders getHeaders() { //headers设定 HttpHeaders httpHeaders = new HttpHeaders(); MediaType mediaType = new MediaType("application","json",Charset.forName("UTF-8")); httpHeaders.setContentType(mediaType); return httpHeaders; } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("微服务连接超时,请重试".getBytes()); } @Override public String getStatusText() throws IOException { //状态文本 return this.getStatusCode().getReasonPhrase(); } @Override public HttpStatus getStatusCode() throws IOException { //fallback时的状态码 return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { //数字类型的状态码 return this.getStatusCode().value(); } @Override public void close() { } }; } }
配置以上,这样出错就会返回如下信息:
微信公众号