如何解决AWS Lambda加载MongoDB Atlas中PNG到Unity Image的报错问题
解决AWS Lambda返回MongoDB存储的Buffer图片导致的内部服务器错误
我将PNG图片以Buffer形式存在MongoDB Atlas中,之前用Express后端能正常获取,但迁移到AWS Lambda后,Unity项目加载图片时持续提示“Internal Server Error”。
原Express后端代码:
exports.tree = function(req, res, next) { Tree.findOne({ level: parseInt(req.params.level) }, "data", function(err, f) { if (err || !f) { res.send(""); return; } res.contentType("image/png"); res.send(f.data); }); };
当前AWS Lambda函数代码:
import { createRequire } from 'module'; const require = createRequire(import.meta.url); const {Tree, config} = require('/opt/nodejs/models'); const mongoose = require('mongoose'); mongoose.set('strictQuery', true); await mongoose.connect(config.DB); function res(body, type="text/plain"){ const res = { statusCode: 200, isBase64Encoded: false, headers: { "Access-Control-Allow-Origin":"*", "Content-Type": type }, multiValueHeader: {}, body }; return res; } export const handler = async(event) => { let f = await Tree.findOne({ level: parseInt(event.queryStringParameters.level,10) }, "data"); if (!f) { return res(""); } return res(f.data,"image/png"); };
Unity端请求代码:
... UnityWebRequest www; if (l > 30) ll = 30; else ll = l; if (!T[ll - 1]){ do { www = UnityWebRequestTexture.GetTexture(Apis.tree+"?level="+ll); yield return www.SendWebRequest(); print(www.downloadedBytes + " Current: " + www.error); } while (www.error != null || www.downloadedBytes == 0); T[ll - 1] = DownloadHandlerTexture.GetContent(www); } Tr.GetComponent<Image>().sprite = Sprite.Create(T[ll - 1], new Rect(0f, 0f, T[ll - 1].width, T[ll - 1].height), new Vector2(0.5f, 0.5f), 100f);
问题核心
AWS Lambda返回二进制数据的规则和Express不同:
- Express可以直接发送Buffer对象作为响应体
- Lambda要求二进制数据必须转为Base64编码的字符串,同时将
isBase64Encoded设为true,否则会把Buffer当成普通字符串处理,导致响应格式错误,触发内部服务器错误。
解决方案
修改Lambda中的响应生成逻辑,针对图片类型做Base64编码处理:
import { createRequire } from 'module'; const require = createRequire(import.meta.url); const {Tree, config} = require('/opt/nodejs/models'); const mongoose = require('mongoose'); mongoose.set('strictQuery', true); // 标记数据库连接状态,避免冷启动重复创建连接 let dbConnected = false; function res(body, type="text/plain"){ let responseBody = body; let isBase64 = false; // 处理图片类型的二进制Buffer数据 if (type === "image/png" && Buffer.isBuffer(body)) { responseBody = body.toString('base64'); isBase64 = true; } return { statusCode: 200, isBase64Encoded: isBase64, headers: { "Access-Control-Allow-Origin":"*", "Content-Type": type }, multiValueHeaders: {}, // 修正原代码拼写错误:multiValueHeader → multiValueHeaders body: responseBody }; } export const handler = async(event) => { // 确保数据库连接成功 if (!dbConnected) { try { await mongoose.connect(config.DB); dbConnected = true; } catch (err) { console.error('数据库连接失败:', err); return res('数据库连接错误', 'text/plain'); } } try { const level = parseInt(event.queryStringParameters?.level, 10); // 校验level参数合法性,避免无效查询 if (isNaN(level)) { return res('无效的level参数', 'text/plain'); } let f = await Tree.findOne({ level }, "data"); if (!f) { return res(""); } return res(f.data,"image/png"); } catch (err) { console.error('查询失败:', err); return res('服务器内部错误', 'text/plain'); } };
额外注意事项
- 数据库连接优化:原代码将
await mongoose.connect放在模块顶层,Lambda冷启动时可能重复创建连接,移到handler内并添加连接状态判断,避免连接溢出。 - 参数校验:增加对
event.queryStringParameters.level的合法性校验,避免因参数格式错误导致查询失败。 - 错误捕获:添加全局try-catch捕获异常,方便排查问题,同时返回明确的错误信息。
- 响应头拼写修正:原代码中
multiValueHeader应为multiValueHeaders(复数形式),拼写错误可能导致响应头异常。
内容的提问来源于stack exchange,提问作者Chong Lip Phang
相关产品推荐
相关产品推荐

