写入 Firebase 存储的零字节文件
Zero btye file written to Firebase storage
我正在将文件从 vuejs 应用程序上传到 firebase 存储。我可以成功写入 firebase 存储,但文件的字节数为零。
文件通过 GraphQL 突变发送到后端:
uploadStream: {
type: GraphQLBoolean,
args: {
id: {
type: GraphQLString
},
file: {
type: GraphQLUpload
}
},
// eslint-disable-next-line no-unused-vars
resolve: async (root, { id, file }, context) => {
const { filename, mimetype, createReadStream } = await file
const stream = createReadStream()
const ext = filename.substr(filename.lastIndexOf('.') + 1)
storageService.upload(id, ext, mimetype, stream)
}
}
然后我这样写入存储:
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
stream.pipe(
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream()
.end()
)
}
我使用 firebase-admin SDK 正在检索存储桶:
const firebaseConfig = {
credential: firebase.credential.cert(JSON.parse(firebase_credential)),
databaseURL: firebase_db,
storageBucket: firebase_storage
}
firebase.initializeApp(firebaseConfig)
const db = firebase.firestore()
const bucket = firebase.storage().bucket()
我不明白为什么上面的代码将零字节文件写入存储。
创建到 Cloud Storage 的写入流后,您立即将其关闭。
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream() // <- opens write stream
.end() // <- immediately closes it
如果 stream
和存储文件的流具有 "error"
事件的侦听器,您会更早发现这一点。
只需删除 .end()
,您的代码就会再次运行:
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
stream.pipe(
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream()
)
}
但是,因为您在 upload()
方法上使用 async
,这意味着您希望它 return 一个 Promise
在上传完成时解析或在失败时拒绝。
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
const storageStream = bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream();
return new Promise((resolve, reject) => {
storageStream.once("finish", resolve); // resolve when written
storageStream.once("error", reject); // reject when either stream errors
stream.once("error", reject);
stream.pipe(storageStream); // pipe the data
});
}
这意味着 resolve:
需要更新为:
resolve: async (root, { id, file }, context) => {
const { filename, mimetype, createReadStream } = await file
const stream = createReadStream()
const ext = filename.substr(filename.lastIndexOf('.') + 1)
return storageService.upload(id, ext, mimetype, stream)
}
我正在将文件从 vuejs 应用程序上传到 firebase 存储。我可以成功写入 firebase 存储,但文件的字节数为零。
文件通过 GraphQL 突变发送到后端:
uploadStream: {
type: GraphQLBoolean,
args: {
id: {
type: GraphQLString
},
file: {
type: GraphQLUpload
}
},
// eslint-disable-next-line no-unused-vars
resolve: async (root, { id, file }, context) => {
const { filename, mimetype, createReadStream } = await file
const stream = createReadStream()
const ext = filename.substr(filename.lastIndexOf('.') + 1)
storageService.upload(id, ext, mimetype, stream)
}
}
然后我这样写入存储:
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
stream.pipe(
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream()
.end()
)
}
我使用 firebase-admin SDK 正在检索存储桶:
const firebaseConfig = {
credential: firebase.credential.cert(JSON.parse(firebase_credential)),
databaseURL: firebase_db,
storageBucket: firebase_storage
}
firebase.initializeApp(firebaseConfig)
const db = firebase.firestore()
const bucket = firebase.storage().bucket()
我不明白为什么上面的代码将零字节文件写入存储。
创建到 Cloud Storage 的写入流后,您立即将其关闭。
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream() // <- opens write stream
.end() // <- immediately closes it
如果 stream
和存储文件的流具有 "error"
事件的侦听器,您会更早发现这一点。
只需删除 .end()
,您的代码就会再次运行:
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
stream.pipe(
bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream()
)
}
但是,因为您在 upload()
方法上使用 async
,这意味着您希望它 return 一个 Promise
在上传完成时解析或在失败时拒绝。
const upload = async (filename, ext, mimetype, stream) => {
const metadata = {
metadata: {
// This line is very important. It's to create a download token.
firebaseStorageDownloadTokens: uuid()
},
contentType: mimetype
}
filename = `profiles/${filename}.${ext}`
const storageStream = bucket
.file(filename, {
gzip: true,
metadata: metadata
})
.createWriteStream();
return new Promise((resolve, reject) => {
storageStream.once("finish", resolve); // resolve when written
storageStream.once("error", reject); // reject when either stream errors
stream.once("error", reject);
stream.pipe(storageStream); // pipe the data
});
}
这意味着 resolve:
需要更新为:
resolve: async (root, { id, file }, context) => {
const { filename, mimetype, createReadStream } = await file
const stream = createReadStream()
const ext = filename.substr(filename.lastIndexOf('.') + 1)
return storageService.upload(id, ext, mimetype, stream)
}