GET请求中Multipart响应图片解析异常,保存后图片损坏求助
问题描述
我尝试读取Multipart响应中的图片并在应用中使用。后端返回两部分内容:第一部分是元数据,第二部分是图片字节数据(存储在PostgreSQL的bytea列)。我用file-saver包保存图片,但遇到了以下问题:
响应示例
--977f8983-13a8-4aea-b8ba-075803ad4790 Content-Disposition: form-data; name="imageData" Content-Type: application/json {"idUser":5} --977f8983-13a8-4aea-b8ba-075803ad4790 Content-Disposition: form-data; name="image" Content-Type: application/octet-stream *image's bytes* --977f8983-13a8-4aea-b8ba-075803ad4790--
尝试的代码及问题
代码1:生成损坏的PNG(大小翻倍)
getImage().then(response => { if (response.status === 200) { return response.formData() } }) .then(fd => { if (fd instanceof FormData) { const blob = new Blob([fd.get('image')],{ type:'image/png' }) saveAs(blob, 'image.png'); } });
结果:得到损坏的PNG文件,大小约为原文件的两倍。
代码2:生成1KB的PNG(内容为网站index.html)
getImage().then(response => { if (response.status === 200) { return response.formData() } }) .then(fd => { if (fd instanceof FormData) { saveAs(fd.get('image'), 'image.png'); } });
结果:保存的文件仅1KB,内容为网站的index.html页面。
补充后端代码
业务逻辑代码
@Inject ImageRepository repository; public Response getUserImage(Long idUser) { var entity = repository.findByIdActiveUser(idUser); var image = new UsrImage(); image.setIdUser(entity.getUsrUserEntity().getId()); var multipartEntity = new MultipartFormDataOutput(); multipartEntity.addFormData("imageData", image, MediaType.APPLICATION_JSON_TYPE); multipartEntity.addFormData("image", entity.getImage(), MediaType.APPLICATION_OCTET_STREAM_TYPE); return Response.ok(multipartEntity,MediaType.MULTIPART_FORM_DATA_TYPE).build(); }
实体类代码
@Entity @Table(name = "usr_image") public class UsrImageEntity { @Id @Basic(optional = false) @NotNull @Column(name = "id_user", nullable = false) private Long idUser; @Basic(optional = false) @NotNull @Type(type = "org.hibernate.type.BinaryType") @Column(nullable = false) private byte[] image; @JoinColumn(name = "id_user", referencedColumnName = "id", nullable = false, insertable = false, updatable = false) @OneToOne(optional = false) private UsrUserEntity usrUserEntity; public byte[] getImage() { return image; } public void setImage(byte[] image) { this.image = image; } public UsrUserEntity getUsrUserEntity() { return usrUserEntity; } public void setUsrUserEntity(UsrUserEntity usrUserEntity) { this.usrUserEntity = usrUserEntity; } }
仓库类代码
@RequestScoped public class UsrImageRepository implements PanacheRepositoryBase<UsrImageEntity, Long>{ public UsrImageEntity findByIdActiveUser(Long idUser) { try{ return find("select f from UsrImageEntity f INNER JOIN UsrUserEntity u ON f.usrUserEntity.id=u.id where u.status = ?1 and u.id = ?2", UserStatusEnum.ACTIVE.toString(),idUser).singleResult(); }catch (NoResultException ex){ Log.info(ex.getMessage()); throw new NotFoundException("There is no image for user id="+idUser); }catch (NonUniqueResultException ex){ Log.info(ex.getMessage()); throw new InternalError(ex.getMessage()); } } }
问题分析与解决方法
核心问题
- 前端解析错误:浏览器自动解析Multipart响应时,可能将二进制图片数据转换为字符串(而非Blob/File对象),导致字节被重复编码,最终生成损坏的文件。
- 后端响应配置缺失:返回Multipart时未指定图片的文件名,且可能存在路由重定向,导致前端拿到index.html内容。
- 数据存储验证:需确认PostgreSQL的bytea列中存储的是原始图片字节,无额外编码。
解决步骤
1. 前端指定响应类型
发起请求时明确标记响应类型为blob,避免浏览器错误解析:
function getImage() { return fetch('/api/user/image/5', { method: 'GET', responseType: 'blob' // 关键配置 }); }
2. 修复前端FormData处理逻辑
确保拿到的图片是Blob类型,再执行保存:
getImage().then(response => { if (response.ok) { return response.formData(); } throw new Error('请求失败'); }).then(fd => { const imageItem = fd.get('image'); if (imageItem instanceof Blob) { saveAs(imageItem, 'image.png'); } else if (typeof imageItem === 'string') { // 若被解析为字符串,转换回原始字节 const uint8Array = new TextEncoder().encode(imageItem); const blob = new Blob([uint8Array], { type: 'image/png' }); saveAs(blob, 'image.png'); } }).catch(err => console.error(err));
3. 后端完善Multipart响应
添加图片文件名参数,避免解析歧义:
// 修改添加image的代码 multipartEntity.addFormData("image", entity.getImage(), MediaType.APPLICATION_OCTET_STREAM_TYPE, "image.png"); // 新增文件名参数
同时检查后端路由,确保无重定向逻辑,直接返回Multipart响应。
4. 验证数据库存储数据
通过SQL查询导出base64编码,验证原始字节是否正确:
SELECT encode(image, 'base64') FROM usr_image WHERE id_user = 5;
将编码内容解码后,确认是有效图片数据。
内容的提问来源于stack exchange,提问作者Hayne
相关产品推荐
相关产品推荐

