调用REST API获取PNG转Base64后浏览器显示损坏图标问题
解决REST API获取PNG图片后Base64编码显示损坏的问题
嘿,我一眼就看出问题出在哪了——你在处理二进制图片响应的时候,错误地把它当成文本在处理,这直接导致Base64编码乱掉,图片自然显示损坏。咱们来一步步修复:
问题到底出在哪?
后端返回的是原始PNG二进制字节流,但你用http.responseText去接收,这会让浏览器把二进制数据当成UTF-8文本解析,过程中很多字节会被错误转换或丢失。之后再用unescape(encodeURIComponent(...))和btoa折腾一遍,编码出来的Base64肯定不对,图片不损坏才怪。
另外还有两个小坑:
- 前端设置
Access-Control-Allow-Origin请求头完全没用,这个头是后端用来告诉浏览器允许跨域的,前端不需要加 - 后端
@CrossOrigin写的是http://localhost:8080,但你前端跑在8888端口,跨域配置不匹配,搞不好还会先触发跨域错误
修复后的代码
前端JavaScript(推荐用Blob方案,简单高效)
把XHR的响应类型改成blob,直接用浏览器的API处理二进制数据,不用手动搞Base64:
function getcap(){ var http = new XMLHttpRequest() http.open("GET", "http://localhost:8888/newcaptcha", true) // 移除没用的Content-Type和Access-Control请求头 http.responseType = "blob"; // 关键:告诉XHR接收二进制Blob http.send() http.onload = () => { if (http.status === 200) { // 直接创建Blob的URL给图片,省得自己编码 const blobUrl = URL.createObjectURL(http.response); const capImg = document.getElementById("capimg"); capImg.src = blobUrl; // 图片加载完记得释放URL,避免内存泄漏 capImg.onload = () => URL.revokeObjectURL(blobUrl); } } }
如果非要用Base64编码的方式,也可以这么写(用ArrayBuffer处理):
function getcap(){ var http = new XMLHttpRequest() http.open("GET", "http://localhost:8888/newcaptcha", true) http.responseType = "arraybuffer"; http.send() http.onload = () => { if (http.status === 200) { // 把ArrayBuffer转成Uint8Array,再转成btoa能处理的字符串 const uint8Array = new Uint8Array(http.response); const binaryStr = String.fromCharCode(...uint8Array); const b64Response = window.btoa(binaryStr); document.getElementById("capimg").src = `data:image/png;base64,${b64Response}`; } } }
后端Java代码(修正跨域配置)
把跨域允许的地址改成前端实际运行的8888端口:
@CrossOrigin(origins = "http://localhost:8888") // 匹配前端端口 @RequestMapping(value = "/newcaptcha", method = RequestMethod.GET, produces = "image/png") public @ResponseBody byte[] getnewCaptcha() { try { Random random = new Random(); imgkey= random.nextInt(3); InputStream is = this.getClass().getResourceAsStream("/"+captcheMap.get(imgkey)+".png"); BufferedImage img = ImageIO.read(is); ByteArrayOutputStream bao = new ByteArrayOutputStream(); ImageIO.write(img, "png", bao); return bao.toByteArray(); } catch (IOException e) { throw new RuntimeException(e); } }
为啥这么改?
responseType: "blob":让XHR直接保留二进制数据的原样,不会被文本解析破坏URL.createObjectURL():浏览器原生API,生成的URL比手动Base64更高效,还能避免编码错误- 跨域配置:后端必须指定前端的实际地址,否则浏览器会拦截跨域请求,连响应都拿不到
内容的提问来源于stack exchange,提问作者jinn
相关产品推荐
相关产品推荐

