HTTP Status 406 - Недопустимо [Потоковая передача огромных данных из бэкэнда с использованием Spring 4.3.x + Java 8] - PullRequest
3 голосов
/ 06 мая 2019

Я использую 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);
    }
}

ИСКЛЮЧЕНИЕ:

enter image description here

ПОСМОТРЕТЬ ПОСЛЕДНИКА

enter image description here ВОПРОС:

Что мне здесь не хватает?

Ответы [ 5 ]

1 голос
/ 07 мая 2019

Эта ошибка говорит о том, что клиент (например, браузер) ожидает, что какой-то контент X (через заголовок Accept, например application / json) будет отправлен сервером, но сервер не предоставляет такой контент на заданной конечной точке (например, создает только XML) ,

В вашем случае вы «принимаете» несколько форматов, но ни один из них не является application/octet-stream, и это то, что вы объявили, что сервер вернется в аннотации @RequestMapping(produces = "application/octet-stream"). Включите это в заголовок браузера Accept.

1 голос
/ 06 мая 2019

406 Недопустимо

Ресурс, идентифицированный запросом, способен генерировать только объекты ответа, характеристики содержимого которых не приемлемы в соответствии с заголовками принятия, отправленными в запросе.

Попробуйте использоватьСоздает аннотацию в вашем методе контроллера:

@Produces({MediaType.APPLICATION_JSON})
1 голос
/ 06 мая 2019

То, что происходит с вами, может быть ошибкой Spring MVC.С браузерами & это также варьируется в зависимости от браузера - заголовок Accept в запросе обязателен с правильными значениями.Вы можете по-разному вести себя в другом браузере, и ваш код может работать в отличном пользовательском интерфейсе.

Согласно скриншоту, ваш заголовок Accept не совпадает с типом ответа, он должен быть */*, так как ваш код особенный в том смысле, что вы не принимаете никаких вводных данных, что является редким сценарием вREST world.

Поэтому я предлагаю добавить расходные элементы в ваше отображение, как показано ниже, и посмотреть, работает ли он,

@RequestMapping(value = "/streamrecords", method = RequestMethod.GET, consumes = MediaType.ALL_VALUE)

и убедиться, что заголовок Accept в запросе содержитзначение - */*.

1 голос
/ 06 мая 2019

Похоже, вам не хватает 2 вещей:

Прежде всего, ваш код возвращает MediaType.APPLICATION_OCTET_STREAM в качестве типа контента.Было бы неплохо, если бы вы сказали Spring, что метод export() производит этот тип.Вы можете сделать это с атрибутом produces @RequestMapping.

Во-вторых, ваш браузер не запрашивает APPLICATION_OCTET_STREAM - вы можете увидеть это по значению заголовка Accept.APPLICATION_OCTET_STREAM отображается на application/octet-stream - ваш запрос от браузера должен будет включить его в значение заголовка Accept, чтобы Spring мог распознать, какой метод следует вызвать в вашем контроллере.

Редактировать:после того, как вы исправите это, взгляните на аннотацию @RestController, которую можно использовать вместо @Controller - вам не нужно будет добавлять аннотацию @ResponseBody, так как она будет включена по умолчанию.Смотрите также @GetMapping, который является наложением для аннотации @RequestMapping для методов HTTP GET.

0 голосов
/ 08 мая 2019

Наконец-то я смог разобраться с этим, что теперь помогает мне передавать огромные данные из бэкэнда во Frontend, используя Spring 4.3.x , как упомянуто в моем посте. Ниже приведены рекомендации, которые помогут вам успешно выполнить программу.

Процедура, описанная ниже, настолько эффективна, что вы даже можете разбивать на страницы огромные данные на бэкэнде (например, hibernate, Mongo-java-driver, cassandra java driver и т. Д.) И продолжать потоковую передачу данных, пока ваша операция db не будет завершена. В некоторых областях, таких как производство, страхование, логистика и т. Д., Вам нужна такая утилита, в которой конечный пользователь ожидает от сервера больших объемов данных в форме CSV, JSON и т. Д. Для анализа необработанных данных.

  1. Добавьте еще одну аннотацию @EnableWebMvc над классом контроллера.

  2. Когда вы добавляете вышеупомянутую аннотацию, код будет прерываться во время выполнения, вы можете увидеть в catalina.log эту ошибку: java.lang.NoClassDefFoundError: com / fastxml / jackson / core / util / DefaultIndenter

  3. Чтобы это исправить, вам нужно добавить ниже зависимость jar в ваш pom.xml

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.8</version>
    </dependency>
    
  4. Теперь добавьте <async-supported>true</async-supported> в web.xml под тегом <servlet>, как показано ниже,

    <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>
    

Ниже приведен код поддержки загрузки потокового файла и потока данных.

Код потока данных:

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

ВЫХОД для обоих потоковых стилей

enter image description here

ПРИМЕЧАНИЕ: Я выполняю обе программы по отдельности, разворачиваю и тестирую их отдельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...