我正在开发一个用于在地图上绘制正在运行的路线并将其保存到mongodb数据库的应用程序。
当前,我正在使用puppeteer来访问应用程序中的路线,并将坐标作为查询字符串传递给地图组件。加载地图后,我将截屏,将返回的Buffer转换为base64编码的字符串,将其保存到数据库,然后使用该字符串在前端显示图像。
整个过程的中间件如下:
exports.screenshotMap = async (req, res, next) => {
try {
const { lineFeatures } = req.body;
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
// open new browser
const page = await browser.newPage();
// create array of coordinates from geojson features
const coords = lineFeatures.map(line => line.geometry.coordinates);
// reduce to 2D array of [lat, lon] coords
const flattenedCoords = coords.reduce((accum, arr) => {
return accum.concat(arr);
}, []);
// Stringify coords before using them as query string
const coordsStr = JSON.stringify(flattenedCoords);
// goto page with map sending coordintaes along
await page.goto(`http://localhost:3000/test?coords=${coordsStr}`, {
waitUntil: 'networkidle0',
});
// wait for map to load, call onLoad callback, and set state to make the h1 visible
await page.waitForSelector('h1');
// wait one more second to make sure all tiles for the map are loaded. Longer routes can require significantly more tiles
await page.waitFor(1000);
const image = await page.screenshot({
type: 'jpeg',
quality: 100,
clip: {
x: 0,
y: 70,
width: 640,
height: 360,
},
omitBackground: true,
});
await browser.close();
// convert buffer to base64 string
const base64Image = await image.toString('base64');
// attach to request object to be used in the next middleware
req.image = base64Image;
next();
} catch (err) {
res.status(400).send(err);
}
};
此方法有效,但是我想知道是否有更好的方法。我已经读到存储Buffer数据更好的用于数据库内存,因为base64字符串很长。更好的方法是保存Buffer数据并将其转换为编码的字符串,然后再将其发送回客户端吗?是否有推荐的方式来处理此类数据?我有兴趣听别人的想法和方法。
答案 0 :(得分:2)
我想出的解决方案是将屏幕截图返回的缓冲区保存到S3存储桶中,然后将唯一的标识符URL存储到我的数据库中。
以下是屏幕截图的中间件:
import puppeteer from 'puppeteer';
//import chromium from 'chrome-aws-lambda';
const takeMapImage = handler => async (req, res) => {
try {
const { lines } = req.body;
// should work for most node projects
const browser = await puppeteer.launch({
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
// if youre using lambda functions
// const browser = await chromium.puppeteer.launch({
// executablePath: await chromium.executablePath,
// args: chromium.args,
// defaultViewport: chromium.defaultViewport,
// headless: chromium.headless,
// });
// open new browser
const page = await browser.newPage();
const url = 'https://yourwebstieurl.com';
await page.goto(
`${url}`,
{
waitUntil: 'networkidle0',
}
);
// provide some waiting time if needed
await page.waitFor(1000);
// image buffer returned from screenshot
const imageBuffer = await page.screenshot({
type: 'jpeg',
quality: 100,
clip: {
x: 0,
y: 0,
width: 640,
height: 360,
},
omitBackground: true,
});
// attach to request object to be used in the next middleware
req.buffer = imageBuffer;
next();
} catch (err) {
console.log(err);
return res
.status(422)
.send({ message: 'there was an error taking picture' });
}
};
然后使用中间件将图像保存到s3。您将需要创建一个存储桶并获取凭据:
import AWS from 'aws-sdk';
import uuid from 'uuid/v1';
// create your s3instance with your credentials
const s3 = new AWS.S3({
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
});
const saveImageToS3 = handler => async (req, res) => {
try {
// use user id as identifier in S3 bucket
const { id } = req.user;
const { buffer } = req;
// s3 file name
const key = `${id}/${uuid()}.jpeg`;
const params = {
Bucket: 'your-bucket-name',
Key: key,
Body: buffer,
ContentEncoding: 'base64',
ContentType: 'image/jpeg',
};
// upload to bucket
const response = await s3.upload(params).promise();
// pass url to next middleware to save to db
req.image = response.Location;
next();
} catch (e) {
console.log(e);
return res.status(422).json({ message: 'user error saving image to s3' });
}
};