后端生成图片传递到前端

后端生成图片返回给前端

环境模拟

运行环境:

复制代码
环境:SpringBoot + Java,生成一张简单 PNG 图片,模拟二维码 / 验证码场景。
依赖:javax.imageio.ImageIO,JDK 自带,不需要额外引入 jar。

前置代码:

java 复制代码
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ImageUtil {
    /**
     * 模拟生成一张图片(二维码/验证码)
     */
    public static BufferedImage createTestImage() {
        int width = 200;
        int height = 200;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = image.createGraphics();
        g2d.setColor(Color.WHITE);
        g2d.fillRect(0,0,width,height);
        g2d.setColor(Color.BLUE);
        g2d.drawString("Demo QrCode",40,100);
        g2d.dispose();
        return image;
    }

    /**
     * image转byte[]字节数组
     */
    public static byte[] imageToBytes(BufferedImage image) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ImageIO.write(image, "png", bos);
        return bos.toByteArray();
    }
}

方式 1: 直接输出二进制字节流

后端:response 输出图片二进制,response.setContentType("image/png"),直接把图片字节写到 response 输出流,不返回 JSON

前端:Ajax 指定responseType:'blob'拿到 Blob,URL.createObjectURL(blob)生成临时 url 赋值 img 的 src。

特点:

优点:图片二进制直接传输,不会增大体积;适合二维码、验证码;

缺点:拿不到业务JSON状态码;Ajax 拿不到res.success;异常只能靠 HTTP 状态码判断;

适用:验证码、二维码图片接口。

示例:

后端

Java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;

@GetMapping("/demo/image/blob")
public void getImageBlob(HttpServletResponse response) throws Exception {
    BufferedImage image = ImageUtil.createTestImage();
    byte[] bytes = ImageUtil.imageToBytes(image);

    response.setContentType("image/png");
    response.setHeader("Cache-Control", "no-cache");

    try(OutputStream out = response.getOutputStream()){
        out.write(bytes);
        out.flush();
    }
}

前端

js 复制代码
$.ajax({
  url:"xxx",
  type:"get",
  xhrFields:{responseType:"blob"}, //解决后端字节流传到前端的乱码问题
  success(blob){
    let objUrl = URL.createObjectURL(blob);  //便于图片标签解析
    $("#img").attr("src",objUrl);
  }
})

注意:用完调用 URL.revokeObjectURL(objUrl)释放内存。

方式 2: Base64 编码返回(返回 JSON,图片放在 data 字段)

后端:把图片转 base64 字符串,封装进 JSON 返回

Java 复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@GetMapping("/demo/image/base64")
@ResponseBody
public Map<String,Object> getImageBase64() throws Exception {
    BufferedImage image = ImageUtil.createTestImage();
    byte[] bytes = ImageUtil.imageToBytes(image);
    //转为base64字符串
    String base64Str = Base64.getEncoder().encodeToString(bytes);

    Map<String,Object> result = new HashMap<>();
    result.put("success",true);
    result.put("data", base64Str);
    result.put("msg","生成成功");
    return result;
}

前端拿到 base64,拼接前缀 data:image/png;base64,,赋值给 img src。

json 复制代码
success:function(res){
    if(res.success){
        $("#img").attr("src","data:image/png;base64," + res.data)
    }
}

特点:

优点:可以携带业务字段(success、msg),可以统一 json 返回格式;

缺点:体积变大,膨胀大约 1.37 倍;大图不建议,适合小图片(二维码、头像)。

不适合大图片,会造成接口返回报文巨大。

方式 3: 后端把图片存文件 / 对象存储,返回图片访问 URL

后端生成图片,保存到服务器本地磁盘 / MinIO/OSS,返回图片 HTTP 访问地址。

json 复制代码
{
  "success":true,
  "data":"http://xxx.oss-cn-beijing.aliyuncs.com/qrcode/xxx.png"
}

前端直接把 url 赋值给 img 的 src,不需要 Ajax 也可以,img 标签直接请求图片

javascript 复制代码
$("#img").attr("src",res.data);

特点:

优点:性能最好;图片由浏览器缓存;接口返回数据很小;适合大量图片;

缺点:要维护存储;需要清理过期图片;需要文件存储服务;

css 复制代码
业务系统首选,大量二维码、海报都用这个。
注意:如果图片需要 token 鉴权,直接 img src 访问会不带 token,后端要做处理。

方式 4: 直接把图片接口地址写死到 img 的 src(不需要 Ajax)

后端接口直接输出图片流,不用 Ajax 请求

css 复制代码
<img src="/***/vcode?url=xxxx" />

浏览器会自动 get 请求这个接口,渲染图片。

特点:

代码最简单,不用写 Ajax;

缺点:无法自定义请求头 token;如果接口需要 token 鉴权,这种方式很难传 token;

css 复制代码
适合不需要登录的验证码、公开二维码;需要鉴权的接口不能直接用 img src。
你的项目如果接口要携带 token,就不能直接写 src,只能用 ajax blob 方式。
方案 核心原理 优点 缺点 适用场景
方案 1:HTTP 二进制字节流(Blob 接收)response 输出图片,前端 ajax+Blob 后端 Response 输出图片二进制,Content‑Type: image/png;前端 Ajax 设置responseType:blobURL.createObjectURL()生成临时地址 1. 原始二进制传输,没有额外体积膨胀,传输效率高2. 支持在 Ajax 请求头携带 Token 做接口鉴权3. 不占用服务器磁盘,图片在内存生成直接输出 1. 响应体是图片,不能同时返回 JSON 业务字段(success/msg) ,异常只能靠 HTTP 状态码判断2. 前端需要手动处理 Blob 对象,用完要调用revokeObjectURL释放内存,否则内存泄漏3. 不能直接缓存业务数据(浏览器可以缓存 http 响应) 二维码、验证码、小尺寸动态图片;接口需要 token 鉴权场景
方案 2:Base64(DataURL)返回 JSON 后端图片转 base64 字符串,放到 JSON 的 data 字段返回;前端拼接data:image/png;base64,xxx赋值 src 1. 标准 JSON 返回,可以同时返回 success、msg 等业务字段,统一项目返回体Ajax 支持 headers 传 Token 鉴权3. 图片直接嵌入页面,不会产生额外网络请求 1.体积膨胀约 1.37 倍,图片越大报文越大,接口响应变慢2. 无法被浏览器缓存,每次都要完整传输字符串3. 大图会造成页面 DOM 数据量大,渲染卡顿 小图片:二维码、头像;需要同时返回业务状态,图片尺寸不大
方案 3:存入对象存储 (OSS/MinIO) 返回 HTTP 访问 URL 后端生成图片,保存到 MinIO/OSS/ 磁盘,返回可访问 http 图片地址,前端直接赋值 img.src 1. 性能最优,图片独立请求,浏览器自带缓存2. 接口返回只有简短 url 字符串,接口报文极小3. 图片可以长期复用,多次前端访问不需要重复生成图片 1. 依赖存储服务,需要维护文件,要处理过期图片清理2. 图片资源请求无法携带 Token 请求头,鉴权需要用临时签名 URL 实现3. 会产生存储流量开销 大量生成的海报、业务二维码;图片需要多次复用;后台大批量导出图片场景
方案 4:img 标签 src 直接调用图片接口 后端输出图片字节流,<img src="图片接口地址" />,浏览器自动发起 get 请求加载图片 1. 前端代码最简单,不需要写 AJAX,一行 html 完成渲染2. 浏览器自动缓存图片 1.无法自定义请求头,不能传递 Token,接口不能做 token 鉴权2. 错误处理麻烦,不方便捕获接口异常 公开无需登录:验证码、无需鉴权的二维码
相关推荐
长栎1 小时前
你写的 AI 品控规则三个月就过期——不是规则错了,是你没给它做"回归测试"
后端
沙湖遇雨1 小时前
7.EventLoop 生命周期
后端
雨落倾城夏未凉1 小时前
halcon核心-模板匹配定位(二)
后端
ma_king1 小时前
Spring Boot 接入飞书自定义机器人
java·后端
2401_894915531 小时前
部署 GEO 优化源码常见报错排查:端口、伪静态、缓存问题解决
java·运维·服务器·后端·缓存·开源
卷无止境1 小时前
聊聊Web开发里的流式数据 从原理到FastAPI实战
后端·python·fastapi
Scene2161 小时前
AgentScope 2.0:4. Message & Event —— 消息模型与事件流深度解析
后端
元界metalite1 小时前
MyBatis 字段改名为何查询不报错?MetaLite ORM 如何做到类型安全?
后端
Csvn2 小时前
🐍 Day 2 :Python 变量与数据类型 — 一切皆对象
后端