想要上传文件,服务器不支持文件流传输怎么办?

​在做开放接口的时候,遇到个问题就是如何通过HTTP上传一个图片,考虑到接口的传输只支持json(API程序的限制),所以优先考虑前端先将图片转成base64字符串,再上传字符串给后端

文件上传方法

​后端在做上传文件到服务器时,需要用到文件流(inputstream),所以这也可以考虑两种方式:

  • 一种是直接上传
  • 另外一种是先将base64转成图片保存到临时路径下,再通过保存的图片拿到文件流。

下面具体看下两种获取流的方式的实现:

直接上传Base64到服务器

方式一:直接上传到服务器(据说没有第二种方式可靠,个人觉得效率会高一些,期间减少了流的操作)

sequenceDiagram
    client->>client: 本地文件转成Base64字符串
    client->>server: http 上传接口
    server->>server: 将Base64转成Bytes数组
    server->>server: 将Bytes数组转成InputStream文件输入流
    server->>server: 保存到文件服务器
    server->>client: 上传成功

实现思路:将base64转成bytes数组,bytes数组再转成输入流;

// 代码实现
//1.将字符串去掉头部信息image转换为byte数组,file为完整的base64字符串
byte[] bytes = new BASE64Decoder().decodeBuffer(file.trim().split(",")[1]);
for (int i = 0; i < bytes.length; ++i) {
    if (bytes[i] < 0) {// 调整异常数据
        bytes[i] += 256;
    }
}
//2.转化为输入流
InputStream imageStream = new ByteArrayInputStream(bytes);

缓存到应用服务器临时路径

方式二:先缓存到临时路径(事后需要删除缓存的图片)

sequenceDiagram
    client->>server: http 上传文件
    server->>server: 将文件暂存到临时路径
    server->>server: 从临时路径读取文件流
    server->>server: 保存到文件服务器
    server->>client: 上传成功
// 代码实现
// 1.调用自己写的帮助类,保存。tempDir为指定的保存路径,包含文件名和后缀
boolean isSave = Base64Convert.generateImage(file, tempDir);
// 2.通过路径找到文件生成一个文件流
InputStream imageStream = new FileInputStream(tempDir);

这种方式需要对文件进行多次写入和读取,开销较大。

经验总结

在开发过程中遇到的坑:上传文件(图片)成功,但是size为0,一开始一直没有找到问题所在,还以为是自己的实现方式有问题,后来经过排查,发现原来是自己调用了一次ImageIO.read(stream),将流给使用了(流只能消费一次),所以后面的流就变了。