HTTP状态406–;不可接受[使用spring 4.3.x+;Java 8从后端流式传输大量数据]

HTTP状态406–;不可接受[使用spring 4.3.x+;Java 8从后端流式传输大量数据],java,spring,spring-mvc,java-8,Java,Spring,Spring Mvc,Java 8,我使用的是SpringMVC4.3.x、Java8和Tomcat7 代码: @Controller public class StreamRecordsController { @RequestMapping(value = "/streamrecords", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE, produces = "application/octet-stream")

我使用的是SpringMVC4.3.x、Java8和Tomcat7

代码:

@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);
    }
}
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);
        }
}
@控制器
公共类StreamRecordsController{
@RequestMapping(value=“/streamrecords”,method=RequestMethod.GET,consumes=MediaType.ALL_值,
products=“应用程序/八位字节流”)
@应答器
公共响应属性导出()引发FileNotFoundException{
File File=新文件(“C:\\Users\\Ankur\\sample.pdf”);
StreamingResponseBody responseBody=输出流->{
copy(file.toPath(),outputStream);
};
返回ResponseEntity.ok()
.header(HttpHeaders.CONTENT\u处置,“附件;文件名=通用文件名\u name.pdf”)
.contentType(MediaType.APPLICATION\u八位字节\u流)
.主体(响应体);
}
}
例外情况:

@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);
    }
}
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);
        }
}

邮差快照

问题:

@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);
    }
}
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);
        }
}

我在这里遗漏了什么?

你似乎遗漏了两件事:

首先,您的代码将返回
MediaType.APPLICATION\u OCTET\u STREAM
作为内容类型。如果您告诉spring,
export()
方法正在生成该类型,那就太好了。您可以使用
@RequestMapping
products
属性来执行此操作

第二件事是,您的浏览器没有要求
应用程序\u八位字节\u流
——您可以通过
接受
标题值看到这一点
APPLICATION\u OCTET\u STREAM
映射到
APPLICATION/OCTET STREAM
-您从浏览器发出的请求需要包含在
Accept
头值中,这样Spring将能够识别应该在控制器中调用的方法

编辑:修复后,请查看可替代
@Controller
使用的
@RestController
注释-您不必添加
@ResponseBody
注释,因为默认情况下它将包含在内。还可以查看HTTP GET方法的
@GetMapping
覆盖的
@RequestMapping
注释。

406不可接受

根据请求中发送的accept标头,由请求标识的资源只能生成具有不可接受内容特征的响应实体

尝试在控制器方法中使用生成注释:

@Produces({MediaType.APPLICATION_JSON})

发生在您身上的可能是Spring MVC错误。对于浏览器&它也因浏览器而异-请求中的Accept标头必须具有正确的值。您可能在不同的浏览器中获得不同的行为,并且您的代码可能在swagger UI中工作

根据您的屏幕截图,您的Accept标头与响应类型不匹配,它应该是
*/*
,因为您的代码非常特殊,您不接受任何输入,这在REST world中是罕见的

因此,我建议在映射中添加消费,如下所示&看看它是否有效

@RequestMapping(value=“/streamrecords”,method=RequestMethod.GET,consumes=MediaType.ALL\u value)


并确保请求中的Accept标头带有值-
*/*

此错误表示客户端(如浏览器)希望服务器发送某种类型的内容X(通过Accept头,如application/json),但服务器不在给定端点上提供此类内容(如仅生成XML)


在您的情况下,您正在“接受”多种格式,但它们都不是
application/octet-stream
,这就是您声明服务器将在
@RequestMapping(products=“application/octet-stream”)
注释中返回的格式。将其包含在您的
Accept
标题浏览器端。

最后,我能够解决这个问题,它现在帮助我使用Spring 4.3.x将大量数据从后端流到前端,正如我在文章中提到的那样。以下是指导您成功执行程序的要点

下面的过程非常有效,您甚至可以在后端对大量数据进行分页(可以是hibernate、Mongo java驱动程序、cassandra java驱动程序等),并继续流式传输数据,除非您的db操作完成。在一些领域,如制造业、保险业、物流业等,您需要这样的实用程序,最终用户希望从服务器以CSV、JSON等形式获取大量数据,以分析原始数据

  • 在控制器类上方再添加一个注释
    @EnableWebMvc

  • 添加上述注释时,代码将在运行时中断,您可以在
    catalina.log
    中看到此错误:

  • 要解决这个问题,您需要在
    pom.xml

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
    
  • 下面是文件流下载和数据流支持的代码

    数据流代码:

    @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);
        }
    }
    
    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);
            }
    }
    
    包com.emg.server.controller.rest;
    导入java.io.IOException;
    导入java.io.OutputStream;
    导入org.springframework.stereotype.Controller;
    导入org.springframework.web.bind.annotation.RequestMapping;
    导入org.springframework.web.bind.annotation.ResponseBody;
    导入org.springframework.web.servlet.config.annotation.EnableWebMvc;
    导入org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
    @控制器
    @EnableWebMvc
    公共类StreamRecordsController{
    @请求映射(value=“/streamrecords”)
    @应答器
    公共StreamIngregatePonsebody导出(){
    返回新的StreamingResponseBody(){
    @凌驾
    public void writeTo(OutputStream out)引发IOException{
    对于(int i=0;i<1000;i++){
    out.write((Integer.toString(i)+“-”)
    .getBytes());
    out.flush();
    试一试{
    睡眠(5);
    }捕捉(中断异常e){