Браузер отображает необработанные данные изображения в формате JPEG.Какие заголовки я должен убедиться в ответе? - PullRequest
10 голосов
/ 21 ноября 2011

Кажется, я столкнулся с интересной проблемой, когда браузер с радостью отображает изображение, сгенерированное моим веб-приложением Spring MVC, если URL-адрес моего контроллера задан как SRC тега IMG, но отображает двоичные данные при прямой навигациина URL.

Мой Spring MVC Controller генерирует некоторую BufferedImage (миниатюру), преобразует ее в byte[] и возвращает ее непосредственно в тело ответа, используя аннотацию @ResponseBody в методе контроллера.Я зарегистрировал конвертер сообщений org.springframework.http.converter.ByteArrayHttpMessageConverter с AnnotationMethodHandlerAdapter и даже установил его свойство supportedMediaTypes на image/jpeg, что не очень помогло, поэтому я вручную устанавливаю заголовок Content-Type в ответе в контроллереmethod.

<img src="/images/thumbnail?id=1234" />

работает нормально и отображает изображение, однако переход непосредственно к SRC изображения (или щелчок правой кнопкой мыши по изображению и выбор View Image) приводит к отображению необработанных данных изображения.

Заголовки ответа, согласно Firebug, получены из запроса на такой URL (http://localhost:8888/images/thumbnail?id=F0snPkvwhtDbl8eutbuq):

HTTP/1.1 200 OK
Expires: Wed, 21 Dec 2011 12:39:07 GMT
Cache-Control: max-age=2592000
Content-Type: image/jpeg
Content-Length: 6998
Server: Jetty(6.1.10)

Последнее слово: в Firebug при нажатии на вкладку Response отображаютсяизображение :-) Что я пропускаю?Я думал, что браузер получает заголовки типа контента и длины контента, знает, что ожидает изображение jpeg, получает необработанные данные для jpeg, а затем отображает jpeg на пустой вкладке браузера.Каким-то образом FF и Chrome отображают необработанные полученные данные изображения.

Код, который я использую:

@RequestMapping(value = "thumbnail", method = { RequestMethod.GET })
@ResponseBody
public byte[] getImageThumbnail(@RequestParam("id") String documentId, HttpServletResponse response) {
    try {
        Document document = documentService.getDocumentById(documentId);
        InputStream imageInputStream = new FileInputStream(document.getUri());
        response.setContentType("image/jpeg");

        BufferedImage img = ImageIO.read(imageInputStream);
        ResampleOp resampleOp = new ResampleOp(THUMBNAIL_DIMENSION);
        BufferedImage thumbnail = resampleOp.filter(img, null);
        return getDataFromBufferedImage(thumbnail);
    } catch (Throwable t) {
        return null; //return no data if document not found or whatever other issues are encountered
    }
}

private byte[] getDataFromBufferedImage(BufferedImage thumbnail) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        ImageIO.write(thumbnail, "jpg", baos);
        baos.flush();
        return baos.toByteArray();
    } finally {
        baos.close();
    }
}

=== ОБНОВЛЕНИЕ === Я следил за @ BalusCСовет и изменил URL, который создает миниатюру, чтобы выглядеть как фактический файл .jpg.Это имело некоторое различие в том, что теперь я могу «Сохранить изображение как», и имя файла больше не просто «миниатюра», а «.jpg», что хорошо.Однако и Chrome, и FF (я даже не начал тестирование в IE) отображают необработанные данные JFIF при загрузке URL-адреса в новую вкладку / окно.Тем не менее, изображение отображается только в том случае, если URL-адрес находится в атрибуте SRC тега IMG и (благодаря кэшированию в браузере), когда пользователь выбирает Просмотр изображения на новой вкладке (но только если пользователь не обновляет вкладку, при обновлении вкладки происходит повторное получениеJPEG и отображение необработанных данных в окне).

EDIT Я только что проверил это в IE9, и это единственный браузер, где он работает, как ожидалось.Я могу перейти к URL-адресу напрямую и продолжать обновлять страницу, и я вижу, что мой контроллер нажимается, и JPEG загружается в окне браузера.Отлично.Теперь, чтобы выяснить, что не так с тем, как FF / CR обрабатывает отправляемый мной JPEG-файл.

Дополнительная информация Я использую Spring version 3.0.6.RELEASE Запуск веб-приложения из Jetty

РЕДАКТИРОВАТЬ Я решил свою проблему с помощью , а не , используя @ResponseBody и BytArrayHttpMessageConverter - я попробовал обходной путь, предложенный в другой теме здесь, на SO - это было простозапишите байты непосредственно в поток вывода ответа: IOUtils.copy(imageInputStream, response.getOutputStream()); Это просто и работает, мне все еще интересно, какова была странная проблема с тем, как браузеры загружали бы ответ в теге <img>, но не непосредственно в окне браузера.Любой может пролить больше света на это, мне было бы очень интересно узнать больше.Сейчас я оставляю этот вопрос без ответа.

Ответы [ 2 ]

2 голосов
/ 25 ноября 2011

Попробуйте обновить аннотацию до:

@RequestMapping(value = "thumbnail", method = { RequestMethod.GET }, produces = {"image/jpeg"})    
@ResponseBody

Примечание produces атрибут.

Надеюсь, это поможет.

1 голос
/ 04 сентября 2013

Я только что решил мою проблему, которая похожа, так что, возможно, вы (или кто-то еще) можете использовать ее. У меня есть иконки, хранящиеся в базе данных PSQL:

create table images (image_id int not null primary key, data bytea)

Мой метод в контроллере:

    @RequestMapping(value = IMAGE + "/{imageId}", method = GET)
    @ResponseBody
    public ResponseEntity<byte[]> getImage(@PathVariable final Integer imageId) throws IOException {
    Image img = imageService.getImage(imageId);
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(MediaType.IMAGE_PNG);
    responseHeaders.set("Content-Disposition", "attachment");
    return new ResponseEntity<byte[]>(img.getData(), responseHeaders, HttpStatus.OK);
}

И так как я использую тимелист , мой HTML выглядит так:

<img src="#" th:src="@{${navigator.IMAGE} + '/-1'}" />

Я поместил imageId = -1 в ссылку только для тестирования. Работает на ФФ.

Надеюсь, это кому-нибудь поможет:)

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