Кажется, я столкнулся с интересной проблемой, когда браузер с радостью отображает изображение, сгенерированное моим веб-приложением 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>
, но не непосредственно в окне браузера.Любой может пролить больше света на это, мне было бы очень интересно узнать больше.Сейчас я оставляю этот вопрос без ответа.