[英]SEVERE: Async timeout for GET [ Streaming huge data Using Spring MVC 4.3.x, Java 8, Tomcat 7 ]
[英]HTTP Status 406 – Not Acceptable [Streaming huge data from backend using spring 4.3.x + Java 8]
我使用的是Spring mvc 4.3.x,java 8,Tomcat 7
码:
@Controller
public class StreamRecordsController {
@RequestMapping(value = "/streamrecords", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE,
produces = "application/octet-stream")
@ResponseBody
public ResponseEntity<StreamingResponseBody> export() throws FileNotFoundException {
File file = new File("C:\\Users\\Ankur\\sample.pdf");
StreamingResponseBody responseBody = outputStream -> {
Files.copy(file.toPath(), outputStream);
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_file_name.pdf")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(responseBody);
}
}
例外:
POSTMAN SNAPSHOT
我在这里错过了什么?
好像你错过了两件事:
首先,您的代码将MediaType.APPLICATION_OCTET_STREAM
作为内容类型返回。 如果你告诉spring export()
方法正在生成那种类型,那就太好了。 为此,您可以用produces
的属性@RequestMapping
。
第二件事是您浏览器不要求APPLICATION_OCTET_STREAM
- 您可以通过Accept
标头值看到它。 APPLICATION_OCTET_STREAM
映射到application/octet-stream
- 来自浏览器的请求需要将它包含在Accept
标头值中,因此Spring将能够识别应该在控制器中调用哪个方法。
编辑:你以后会解决这个问题,采取一看@RestController
注释,可以用来代替@Controller
-你不会有加@ResponseBody
注解,因为它会在默认情况下被包括在内。 另请@GetMapping
,它是HTTP GET方法的@RequestMapping
注释的叠加层。
406不可接受
由请求标识的资源仅能够根据请求中发送的接受报头生成具有不可接受的内容特征的响应实体。
尝试在控制器方法中使用Produces annotation:
@Produces({MediaType.APPLICATION_JSON})
你发生的事情可能是一个Spring MVC bug。 对于浏览器,它也因浏览器而异 - 请求中的Accept标头必须具有正确的值。 您可能会在不同的浏览器中获得不同的行为,并且您的代码可能在swagger UI中工作。
根据您的屏幕截图,您的Accept标头与响应类型不匹配,它应该是*/*
因为您的代码是特殊的,因为您不接受任何输入,这是REST世界中罕见的情况。
因此,我建议您在地图中添加耗材,如下所示,看看它是否有效,
@RequestMapping(value = "/streamrecords", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)
并确保请求中的Accept标头带有值 - */*
。
此错误表示客户端(例如浏览器)期望某种内容X(通过Accept标头,例如application / json)由服务器发送,但服务器不在给定端点上提供此类内容(例如,仅生成XML)。
在您的情况下,您“接受”多种格式,但它们都不是application/octet-stream
,而是您声明服务器将在@RequestMapping(produces = "application/octet-stream")
注释中返回的内容。 在您的Accept
标头浏览器端包含它。
最后,我能够对此进行排序,现在正在帮助我使用我在帖子中提到的Spring 4.3.x从后端向前端传输大量数据。 以下是指导您成功执行程序的要点。
下面的过程非常有效,您甚至可以在后端对大量数据进行分页(可以是hibernate,Mongo-java-driver,cassandra java驱动程序等),并继续流式传输数据,除非您的数据库操作完成。 在制造,保险,物流等领域,您需要这样的实用程序,其中最终用户希望以CSV,JSON等形式从服务器获取安静的大数据来分析原始数据。
在控制器类上方再添加一个注释@EnableWebMvc
。
当你添加上面的注释时,代码将在运行时中断,你可以在catalina.log
看到,这个错误: java.lang.NoClassDefFoundError:com / fasterxml / jackson / core / util / DefaultIndenter
要解决此问题,您需要在pom.xml
添加以下jar依赖项
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
现在,在<servlet>
标记下的web.xml
添加<async-supported>true</async-supported>
,如下例所示,
<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet>
以下是FILE Streaming Download和Data Stream支持的代码。
数据流代码:
package com.emg.server.controller.rest;
import java.io.IOException;
import java.io.OutputStream;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Controller
@EnableWebMvc
public class StreamRecordsController {
@RequestMapping(value = "/streamrecords")
@ResponseBody
public StreamingResponseBody export() {
return new StreamingResponseBody() {
@Override
public void writeTo (OutputStream out) throws IOException {
for (int i = 0; i < 1000; i++) {
out.write((Integer.toString(i) + " - ")
.getBytes());
out.flush();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
}
}
文件流代码:
package com.emg.server.controller.rest;
import java.io.File;
import java.nio.file.Files;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Controller
@EnableWebMvc
public class StreamRecordsController {
@RequestMapping(value = "/streamrecords", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
@ResponseBody
public ResponseEntity<StreamingResponseBody> export() {
File file = new File("C:\\Users\\Ankur\\sample.pdf");
StreamingResponseBody responseBody = outputStream -> {
Files.copy(file.toPath(), outputStream);
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_file_name.pdf")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(responseBody);
}
}
OUTPUT用于流式传输
注意:我单独执行这两个程序,部署并单独测试它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.