浏览器显示 jpeg 的原始图像数据。我应该确保响应中包含哪些标头?
我似乎遇到了一个有趣的问题,只要我的控制器的 URL 设置为 IMG 标记的 SRC,浏览器就会愉快地显示由 Spring MVC Web 应用程序生成的图像,但在直接导航到该 URL 时会显示二进制数据。
我的 Spring MVC 控制器生成一些 BufferedImage
(缩略图),将其转换为 byte[]
并使用 @ResponseBody
将其直接返回到响应正文中控制器方法上的注释。我已经使用 AnnotationMethodHandlerAdapter
注册了一个 org.springframework.http.converter.ByteArrayHttpMessageConverter
消息转换器,甚至将其 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 中,单击响应选项卡显示图像:-) 我错过了什么?我认为浏览器接收内容类型和内容长度标头,知道需要 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 上进行测试)在将 URL 加载到新选项卡/窗口时都会显示原始 JFIF 数据。尽管如此,只有当 URL 位于 IMG 标签的 SRC 属性中并且(由于浏览器缓存)用户选择在新选项卡中查看图像时,图像才会显示(但前提是用户不刷新选项卡,刷新选项卡将重新获取) JPEG 并在窗口中显示原始数据)。
编辑 我刚刚在 IE9 中对此进行了测试,这是唯一可以按预期工作的浏览器。我可以直接导航到 URL 并不断刷新页面,我可以看到我的控制器被点击,并且 JPEG 已加载到浏览器窗口中。出色的。现在要弄清楚 FF/CR 处理我发送的 JPEG 的方式有什么问题。
其他信息 我正在使用 Spring 版本 3.0.6.RELEASE 从 Jetty 运行网络应用
编辑 我已经通过 not 使用 @ResponseBody
和 BytArrayHttpMessageConverter
解决了我的问题 - 我尝试了在另一个线程中提出的解决方法 - 那就是将字节直接写入响应输出流: IOUtils.copy(imageInputStream, response.getOutputStream());
这很简单并且有效,我仍然很好奇浏览器的奇怪问题是什么加载在 标记中响应,但不直接在浏览器窗口中响应。任何人都可以对此有更多的了解,我真的很想了解更多信息。我暂时不回答这个问题。
I seem to have run into an interesting problem where the browser happily displays an image generated by my Spring MVC web application as long as the URL to my controller is set as SRC of an IMG tag, but displays binary data when navigated directly to the URL.
My Spring MVC Controller generates some BufferedImage
(thumbnail), converts it to byte[]
and returns it directly into the response body using the @ResponseBody
annotation on the controller method. I have registered a org.springframework.http.converter.ByteArrayHttpMessageConverter
message converter with the AnnotationMethodHandlerAdapter
and even set its supportedMediaTypes
property to image/jpeg
, which wasn't really helping, so I am setting the Content-Type header on the response manually in the controller method.
<img src="/images/thumbnail?id=1234" />
works fine and displays the image, however navigating directly to the SRC of the image (or right-clicking the image and choosing View Image) ends up displaying the raw data of the image.
Response headers, according to Firebug, received from a request to such URL (http://localhost:8888/images/thumbnail?id=F0snPkvwhtDbl8eutbuq) are:
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)
One last word: in Firebug, clicking on the Response tab displays the image :-) What am I missing out? I thought the browser receives the content-type and content-length headers, knows to expect jpeg image, receives raw data for the jpeg, then displays jpeg in the empty browser tab. Somehow FF, and Chrome are displaying raw image data received.
Code I am using:
@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 ===
I have followed @BalusC's advice and changed the url that produces the thumbnail to look like an actual .jpg file. This has made some difference in that now I can "Save image as" and the file name is no longer just "thumbnail" but ".jpg" which is good. However, both Chrome and FF (I have not even begun testing on IE) display raw JFIF data when loading the URL into a fresh tab/window. Still, image only displays if the URL is in the SRC attribute of an IMG tag and (thanks to browser caching) when user selects View image in new tab (but only if user does not refresh the tab, refreshing the tab will re-fetch the JPEG and display raw data in the window).
EDIT
I have just tested this in IE9 and this is the only browser where it works as expected. I can navigate to the URL directly and keep refreshing the page and I can see my controller being hit and the JPEG is loaded in the browser window. Excellent. Now to figure out what is wrong with the way FF/CR handle the JPEG I am sending.
Additional info
I am using Spring version 3.0.6.RELEASE
Running web app from Jetty
EDIT
I have solved my problem by not using @ResponseBody
and BytArrayHttpMessageConverter
- I tried the workaround proposed in another thread here on SO - that was to just write the bytes directly into the response output stream: IOUtils.copy(imageInputStream, response.getOutputStream());
This is straightforward and works, I am still curious what was the weird problem with how the browsers would load the reponse in an <img>
tag but not directly in a browser window. Anyone can shed more light on this, I would be really curious to find out more. I am leaving this question unanswered for now.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试将注释更新为:
Note
Produces 属性。
希望有帮助。
Try to update your annotation to:
Note
produces
attribute.Hope that helps.
我刚刚解决了类似的问题,所以也许您(或其他人)可以利用它。我在 psql 数据库中存储了图标:
我在控制器中的方法是:
由于我使用 thymeleaf 我的 html 看起来像这样:
我将 imageId = -1 放在链接中只是为了测试。它适用于 FF。
希望它对某人有帮助:)
I just resolved my problem which is similar so maybe you (or someone else) can make use of it. I have icons stored in psql database:
My method in controller is:
And since I'm using thymeleaf my html looks like this:
I put imageId = -1 in link just for testing. It works on FF.
Hope it helps someone :)