如何使用 Node.js 将 base64 编码图像(字符串)直接上传到 Google Cloud Storage 存储桶?
Posted
技术标签:
【中文标题】如何使用 Node.js 将 base64 编码图像(字符串)直接上传到 Google Cloud Storage 存储桶?【英文标题】:How do I upload a base64 encoded image (string) directly to a Google Cloud Storage bucket using Node.js? 【发布时间】:2017-08-10 06:42:49 【问题描述】:目前,我正在使用@google-cloud/storage NPM 包将文件直接上传到 Google Cloud Storage 存储桶。这需要一些技巧,因为我只有图像的 base64 编码字符串。我必须:
解码字符串 另存为文件 将文件路径发送到以下脚本以上传到 Google Cloud Storage 删除本地文件我想避免将文件完全存储在文件系统中,因为我使用的是 Google App Engine,并且我不想让文件系统过载/如果删除操作因任何原因不起作用,我不想将垃圾文件留在那里。这是我的上传脚本现在的样子:
// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var base64Img = require('base64-img');
var filePath = base64Img.imgSync(req.body.base64Image, 'user-uploads', 'image-name');
// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
bucket = gcs.bucket('google-cloud-storage-bucket-name');
// Upload the image to the bucket
bucket.upload(__dirname.slice(0, -15) + filePath,
destination: 'profile-images/576dba00c1346abe12fb502a-original.jpg',
public: true,
validation: 'md5'
, function(error, file)
if (error)
sails.log.error(error);
return res.ok('Image uploaded');
);
有没有办法直接上传图片的base64编码字符串,而不必转换成文件再使用路径上传?
【问题讨论】:
bucket.upload
包装了file.createWriteStream
函数,因此您需要将base64 文件字符串通过管道传送到file
中由该方法创建的流中。我建议只写入文件系统并在上传后取消链接。我认为您在删除文件时不会遇到问题。如果您愿意,我也许可以举一个例子。
@forrestmid 非常感谢您如何实现file.createWriteStream
以直接上传的示例。谢谢!
【参考方案1】:
我认为,解决方案是使用 file.createWriteStream
函数,该函数封装在 Google Cloud Node SDK 中。
我对流的经验很少,所以如果这不起作用,请多多包涵。
首先,我们需要获取 base64 数据并将其放入流中。为此,我们将包含 stream
库,从 base64 数据创建缓冲区,并将缓冲区添加到流的末尾。
var stream = require('stream');
var bufferStream = new stream.PassThrough();
bufferStream.end(Buffer.from(req.body.base64Image, 'base64'));
更多关于decoding base64 和creating the stream。
然后,我们将流传输到由file.createWriteStream
函数创建的写入流中。
var gcs = require('@google-cloud/storage')(
projectId: 'grape-spaceship-123',
keyFilename: '/path/to/keyfile.json'
);
//Define bucket.
var myBucket = gcs.bucket('my-bucket');
//Define file & file name.
var file = myBucket.file('my-file.jpg');
//Pipe the 'bufferStream' into a 'file.createWriteStream' method.
bufferStream.pipe(file.createWriteStream(
metadata:
contentType: 'image/jpeg',
metadata:
custom: 'metadata'
,
public: true,
validation: "md5"
))
.on('error', function(err) )
.on('finish', function()
// The file upload is complete.
);
file.createWriteStream
、File docs、bucket.upload
和 bucket.upload
method code in the Node SDK 的信息。
所以上面代码的工作方式是定义你要放入文件的桶,然后定义文件和文件名。我们不在这里设置上传选项。然后,我们将刚刚创建的bufferStream
变量通过管道传输到我们之前讨论过的file.createWriteStream
方法中。在这些选项中,我们定义了您想要实现的元数据和其他选项。直接查看Node code on Github 以了解它们如何分解bucket.upload
函数非常有帮助,并建议您也这样做。最后,我们为上传完成和出错的时间附加了几个事件。
【讨论】:
感谢您发布此消息!我实际上做了类似的事情,除了我使用了file.save() API,它是createWriteStream
的环绕。
@Nag 这绝对有效!我通读了该 API,但没有注意到它的操作与您正在寻找的操作相匹配。很高兴你能弄明白。
@Nag 你到底是怎么做到的?你有源代码我们可以看看吗?我为此苦苦挣扎。我正在尝试从 Firebase Cloud Functions 将 base64 编码的图像字符串上传到 Firebase 存储
@krlozadan 请在下面查看我的回答。我不确定 Cloud Storage 和 Firebase Storage 之间有什么区别,所以我无法评论 Firebase。希望这会有所帮助。
请注意,由于安全问题,不推荐使用 Buffer 构造函数。我们应该改用Buffer.from(req.body.base64Image, 'base64')
。【参考方案2】:
响应@krlozadan 的上述请求,发布我的答案版本:
// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var mimeTypes = require('mimetypes');
var image = req.body.profile.image,
mimeType = image.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/)[1],
fileName = req.profile.id + '-original.' + mimeTypes.detectExtension(mimeType),
base64EncodedImageString = image.replace(/^data:image\/\w+;base64,/, ''),
imageBuffer = new Buffer(base64EncodedImageString, 'base64');
// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
bucket = gcs.bucket('my-bucket');
// Upload the image to the bucket
var file = bucket.file('profile-images/' + fileName);
file.save(imageBuffer,
metadata: contentType: mimeType ,
public: true,
validation: 'md5'
, function(error)
if (error)
return res.serverError('Unable to upload the image.');
return res.ok('Uploaded');
);
这对我来说效果很好。忽略前几行中的一些附加逻辑,因为它们仅与我正在构建的应用程序相关。
【讨论】:
【参考方案3】:如果您想将字符串保存为 Google Cloud Storage 中的文件,您可以使用 file.save
方法轻松完成:
const Storage = require('@google-cloud/storage');
const storage = new Storage();
const myBucket = storage.bucket('my-bucket');
const file = myBucket.file('my-file.txt');
const contents = 'This is the contents of the file.';
file.save(contents).then(() => console.log('done'));
【讨论】:
问题是关于上传“base64 编码图像”。这不起作用。 如果您将contents
设置为此,这适用于base64 字符串,其中data
是base64 编码文件:Buffer.from(data.replace(/^data:image\/(png|gif|jpeg);base64,/, ''), 'base64');
【参考方案4】:
:) 什么问题!!已经尝试过并得到了问题图像已上传到firebase存储但没有下载,只是加载器正在四处移动......花了一些时间......成功通过下载将图像上传到firebase存储......有访问令牌中的问题...
check the screenshot
如果您检查右侧底部的文件位置部分,则有一个“创建访问令牌”选项,如果您在那里手动创建访问令牌,则此处不会显示任何“访问令牌”,然后刷新页面图像将显示...所以现在的问题是如何通过代码创建它...
只需使用以下代码创建访问令牌
const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: firebaseStorageDownloadTokens: uuid
下面给出了将图像上传到firebase存储上的存储图像的完整代码
const functions = require('firebase-functions')
var firebase = require('firebase');
var express = require('express');
var bodyParser = require("body-parser");
const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
const os = require('os')
const path = require('path')
const cors = require('cors')( origin: true )
const Busboy = require('busboy')
const fs = require('fs')
var admin = require("firebase-admin");
var serviceAccount =
"type": "service_account",
"project_id": "xxxxxx",
"private_key_id": "xxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
"client_email": "xxxx@xxxx.iam.gserviceaccount.com",
"client_id": "xxxxxxxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
admin.initializeApp(
credential: admin.credential.cert(serviceAccount),
storageBucket: "xxxxx-xxxx" // use your storage bucket name
);
const app = express();
app.use(bodyParser.urlencoded( extended: false ));
app.use(bodyParser.json());
app.post('/uploadFile', (req, response) =>
response.set('Access-Control-Allow-Origin', '*');
const busboy = new Busboy( headers: req.headers )
let uploadData = null
busboy.on('file', (fieldname, file, filename, encoding, mimetype) =>
const filepath = path.join(os.tmpdir(), filename)
uploadData = file: filepath, type: mimetype
console.log("-------------->>",filepath)
file.pipe(fs.createWriteStream(filepath))
)
busboy.on('finish', () =>
const bucket = admin.storage().bucket();
bucket.upload(uploadData.file,
uploadType: 'media',
metadata:
metadata: firebaseStorageDownloadTokens: uuid,
contentType: uploadData.type,
,
,
)
.catch(err =>
res.status(500).json(
error: err,
)
)
)
busboy.end(req.rawBody)
);
exports.widgets = functions.https.onRequest(app);
【讨论】:
感谢分享您的代码!您能否分享一下您的请求是如何格式化的(POST 请求的正文是什么?)【参考方案5】:您必须将base64转换为图像缓冲区然后上传如下,您需要提供image_data_from_html
变量作为您从HTML事件中提取的数据。
const base64Text = image_data_from_html.split(';base64,').pop();
const imageBuffer = Buffer.from(base64Text, 'base64');
const contentType = data.image_data.split(';base64,')[0].split(':')[1];
const fileName = 'myimage.png';
const imageUrl = 'https://storage.googleapis.com/bucket-url/some_path/' + fileName;
await admin.storage().bucket().file('some_path/' + fileName).save(imageBuffer,
public: true,
gzip: true,
metadata:
contentType,
cacheControl: 'public, max-age=31536000',
);
console.log(imageUrl);
【讨论】:
值得指出的是,如果你的 base64 编码字符串实际上是一个 dataURL(参见:developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/…),就像你从画布或织物生成的那样,那么你需要这个解决方案的第一行来摆脱额外的 URL 部分。为我工作。【参考方案6】:我只需一行代码就能将 base64 字符串传输到我的 Cloud Storage 存储桶。
var decodedImage = new Buffer(poster64, 'base64');
// Store Poster to storage
let posterFile = await client.file(decodedImage, `poster_$path.jpeg`, path: 'submissions/dev/', isBuffer: true, raw: true );
let posterUpload = await client.upload(posterFile, metadata: cacheControl: 'max-age=604800' , public: true, overwrite: true );
let permalink = posterUpload.permalink
需要注意的是,如果您在 Nodejs 环境中,您将无法使用 atob()。
这篇文章的最佳答案向我展示了我的方式的错误! NodeJS base64 image encoding/decoding not quite working
【讨论】:
不确定你从哪里得到isBuffer: true, raw: true
-- 我在 SDK 中看不到这些。以上是关于如何使用 Node.js 将 base64 编码图像(字符串)直接上传到 Google Cloud Storage 存储桶?的主要内容,如果未能解决你的问题,请参考以下文章
将 base64 图像字符串转换为可以使用 node.js 提供给浏览器的图像文件
node.js - 带有 base64 的 http [重复]
获取 Base64 编码的图像并使用 ExpressJS 作为图像发送