浏览器显示 jpeg 的原始图像数据。我应该确保在响应中包含哪些标题?

Posted

技术标签:

【中文标题】浏览器显示 jpeg 的原始图像数据。我应该确保在响应中包含哪些标题?【英文标题】:Browser displays raw image data of jpeg. What headers should I make sure to have in the response? 【发布时间】:2012-01-02 23:08:15 【问题描述】:

我似乎遇到了一个有趣的问题,只要将控制器的 URL 设置为 IMG 标记的 SRC,浏览器就会愉快地显示由我的 Spring MVC Web 应用程序生成的图像,但直接导航时会显示二进制数据到网址。

我的 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”,这很好。然而,当将 URL 加载到新的选项卡/窗口时,Chrome 和 FF(我什至还没有开始在 IE 上进行测试)都会显示原始 JFIF 数据。尽管如此,图像仅在 URL 位于 IMG 标签的 SRC 属性中时显示,并且(由于浏览器缓存)当用户选择在新选项卡中查看图像时(但仅当用户不刷新选项卡时,刷新选项卡将重新获取JPEG 并在窗口中显示原始数据)。

编辑 我刚刚在 IE9 中对此进行了测试,这是唯一可以按预期工作的浏览器。我可以直接导航到 URL 并不断刷新页面,我可以看到我的控制器被点击并且 JPEG 被加载到浏览器窗口中。优秀。现在要弄清楚 FF/CR 处理我发送的 JPEG 的方式有什么问题。

其他信息 我正在使用 Spring 版本 3.0.6.RELEASE 从 Jetty 运行 Web 应用程序

编辑 我已经通过 not 使用 @ResponseBodyBytArrayHttpMessageConverter 解决了我的问题 - 我尝试了 SO 上另一个线程中提出的解决方法 - 那就是直接将字节写入响应输出流:@ 987654333@ 这很简单并且有效,我仍然很好奇浏览器如何在&lt;img&gt; 标签中加载响应而不是直接在浏览器窗口中加载响应的奇怪问题是什么。任何人都可以对此有所了解,我真的很想知道更多。我暂时不回答这个问题。

【问题讨论】:

你能把返回的 baos.toByteArray() 放在 之后吗? 好的,做到了。没有解决我的问题,但现在看起来好多了:-) 仍然不太可能,但 ImageIO.write 带有“jpeg” i.o。 “jpg”似乎是在 API 中使用的。应该双向工作。可能是不同的标记字节。 以前在 FF/Chrome 上从未见过这种情况。我希望 MSIE 上会出现这种问题,因为它首先根据 URL 而不是响应标头识别下载内容的内容类型。无论如何,如果您向 URL 映射添加扩展名,例如 thumbnail.jpg,会发生什么? 【参考方案1】:

我刚刚解决了我的类似问题,所以也许您(或其他人)可以使用它。我有存储在 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);

由于我使用的是thymeleaf,所以我的 html 看起来像这样:

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

我将 imageId = -1 放在链接中只是为了测试。它适用于 FF。

希望它可以帮助某人:)

【讨论】:

【参考方案2】:

尝试将您的注释更新为:

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

注意produces 属性。

希望对您有所帮助。

【讨论】:

如果在我使用的 spring 版本中仅支持 requestmapping 的生产属性,这可能会有所帮助。我正在使用 Spring 3.0.6.RELEASE 这是在 3.1 M2 中添加的,不过感谢您的建议。 这并不能解释它在 &lt;img&gt; 中工作但在新选项卡/窗口中不起作用的症状。

以上是关于浏览器显示 jpeg 的原始图像数据。我应该确保在响应中包含哪些标题?的主要内容,如果未能解决你的问题,请参考以下文章

关于DeepLearning的学习数据(jpeg)和嵌入式系统(原始)的区别

使用JavaScript从JPEG访问原始YUV值

处理 JPEG 图像中的多余系数

将字节数组转换/显示为 bmp/jpeg 图像

在客户端的 JavaScript 中访问 JPEG EXIF 旋转数据

nodejs将原始图像数据写入jpeg文件?