You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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());
        }
    }
    
}

问题分析与解决方法

核心问题

  1. 前端解析错误:浏览器自动解析Multipart响应时,可能将二进制图片数据转换为字符串(而非Blob/File对象),导致字节被重复编码,最终生成损坏的文件。
  2. 后端响应配置缺失:返回Multipart时未指定图片的文件名,且可能存在路由重定向,导致前端拿到index.html内容。
  3. 数据存储验证:需确认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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 23:45:45