Кажется, я столкнулся с интересной проблемой, когда браузер с радостью отображает изображение, сгенерированное моим веб-приложением Spring MVC, пока URL-адрес моего контроллера установлен как SRC тега IMG, но отображает двоичные данные, когда перейдите непосредственно к URL-адресу.
My Spring MVC Controller генерирует некоторый BufferedImage
(миниатюра), преобразует его в byte[]
и возвращает его непосредственно в тело ответа с помощью аннотации @ResponseBody
в методе контроллера. Я зарегистрировал конвертер сообщений org.springframework.http.converter.ByteArrayHttpMessageConverter
с AnnotationMethodHandlerAdapter
и даже установил его свойство supportedMediaTypes
на image/jpeg
, что на самом деле не помогло, поэтому я устанавливаю заголовок Content-Type в ответе вручную в контроллере метод.
<img src="/images/thumbnail?id=1234" />
отлично работает и отображает изображение, однако переход непосредственно к SRC изображения (или щелчок правой кнопкой мыши по изображению и выбор вида изображения) заканчивается отображением необработанных данных изображения.
Заголовки ответов в соответствии с 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();
}
}
=== UPDATE === Я последовал совету @BalusC и изменил URL-адрес, который создает миниатюру, чтобы выглядеть как фактический файл .jpg. Это в определенной степени повлияло на то, что теперь я могу "Сохранить изображение как", и имя файла больше не просто "thumbnail", а ".jpg", что хорошо. Тем не менее, как Chrome, так и FF (я даже не начал тестировать в IE) отображают необработанные данные JFIF при загрузке URL в новую вкладку/окно. Тем не менее, изображение отображается только в том случае, если URL-адрес находится в атрибуте SRC тега IMG и (благодаря кешированию браузера), когда пользователь выбирает View image на новой вкладке (но только если пользователь не обновляет вкладку, обновление вкладки будет повторно выбрано JPEG и отобразить необработанные данные в окне).
ИЗМЕНИТЬ Я только что протестировал это в IE9, и это единственный браузер, где он работает так, как ожидалось. Я могу перейти непосредственно к URL-адресу и продолжить обновление страницы, и я вижу, что мой контроллер попал, а JPEG загружен в окне браузера. Отлично. Теперь, чтобы понять, что не так с тем, как FF/CR обрабатывает JPEG, который я отправляю.
Дополнительная информация Я использую Spring версию 3.0.6.RELEASE Запуск веб-приложения из Jetty
ИЗМЕНИТЬ
Я решил свою проблему с помощью не с помощью @ResponseBody
и BytArrayHttpMessageConverter
- я попробовал обходное решение, предложенное в другом потоке здесь, на SO -, чтобы просто написать байты непосредственно в выходной поток ответа: IOUtils.copy(imageInputStream, response.getOutputStream());
Это прямолинейно и работает, мне все же любопытно, какая была странная проблема с тем, как браузеры будут загружать ответ в теге <img>
, но не непосредственно в окне браузера. Любой может пролить свет на это, мне было бы очень интересно узнать больше. Я оставляю этот вопрос без ответа.