我使用云存储正在经历不一致的行为似乎与留档相反的文件上传器。
当您将对象上传到云存储并收到成功响应时,该对象可立即从Google提供服务的任何位置进行下载和元数据操作。无论创建新对象还是替换现有对象,这都是正确的。因为上载是高度一致的,所以对于写入后读取或更新后读取的操作,您将永远不会收到404未找到响应或过时的数据。https://cloud.google.com/storage/docs/consistency#strongly_consistent_operations
... 但如果我在上传后立即阅读,我会收到404。
流程如下:
我得到了它所有的工作,但然后发现,当一个新文件上传(即不已经存在于桶),有一个500ms的延迟之间的上传完成(步骤2)和读取成功(步骤4)。如果我毫不拖延地做这件事,我会得到404分。
文档中说,除非有缓存,否则通常可以立即上传。
重要提示:公开可读的缓存对象可能不会表现出强一致性。有关详细信息,请参阅缓存控制和一致性。
我正在使用XMLHttpRequest
将文件上传到GCS,并使用load
事件来检测完成的上载。据我所知,这应该意味着已经收到了200个响应,因此文件已经到位。尽管调试加载事件显示它只是100%的另一个“进度”事件。
我试过的
解决方法是在第3步调用我的应用编程接口之前,在加载事件处理程序中的最后一个回调中添加一个setTimeout(完成,500)
。
我已经对此进行了几十次测试,它是可靠的,在0-400ms出现故障时可重复,而在500ms左右“修复”它。
我尝试过按照建议将缓存控制头添加到原始POST,这将上传会话设置为没有缓存-添加no-store
,这似乎是正确的。我可以在PUT的标题中看到这一点(它实际上在响应中放置了比我设置的更多的无缓存选项)。这似乎根本没有影响行为。
如果文件已经在bucked中并被覆盖,则不会发生这种情况。(虽然我猜如果我上传了不同的文件,内容中可能仍然存在竞争条件)。
我似乎无法捕获异常,因此我不知道是哪个对GCS的调用返回404,无论是bucket.file()
还是remoteFile.createReadStream()
,还是稍后从中读取(在我将可读流传递到的其他库的深处)。
我没有尝试尝试/重试循环,因为我甚至无法捕获错误。如果我不能保证一致的行为,这就是我想做的。
我试过使用gcs可恢复上传软件包和直接使用Storage.File,两者似乎都是一样的。
启动上载的NodeJS API如下所示:
1a) gcs-resumable-upload
版本
const {createURI} = require('gcs-resumable-upload');
const sessionURI = await createURI({
bucket: bucketName,
file: filename,
origin: origin,
customRequestOptions: { //todo: this doesn't fixe the race
headers: {
'Cache-Control': 'no-store',
},
},
});
1b)Storage.File
version
const {Storage, File} = require('@google-cloud/storage');
const storage = new Storage();
const bucket = storage.bucket(bucketName);
const file = bucket.file(filename);
const resp = await file.createResumableUpload({origin: origin})
const sessionURI = resp[0];
var reader = new FileReader();
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("load", function(e){
setTimeout(done, 500);// todo I get 404s in the next step without 500ms delay?
// done(); // fails
}, false);
xhr.open("PUT", sessionUrl);
xhr.overrideMimeType('text/plain; charset=x-user-defined-binary');
reader.onload = function(evt) {
xhr.send(evt.target.result);
};
reader.readAsBinaryString(file);
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const bucket = storage.bucket(bucketName);
let remoteFile, stream;
remoteFile = bucket.file(filename);
stream = remoteFile.createReadStream()
流
然后返回并发送到一个库,该库使用它读取内容。
这就是它出错的地方,尽管它在tick事件中出错为异步,而且我还没有设法从任何地方尝试/捕获它(这有点奇怪)。
错误
错误堆栈为:
<ref *2> ApiError: No such object: MY-BUCKETNAME/MY-FILENAME
at new ApiError (node_modules/@google-cloud/common/build/src/util.js:59:15)
at Util.parseHttpRespMessage (node_modules/@google-cloud/common/build/src/util.js:161:41)
at Util.handleResp (node_modules/@google-cloud/common/build/src/util.js:135:76)
at Duplexify.<anonymous> (node_modules/@google-cloud/storage/build/src/file.js:880:31)
at Duplexify.emit (events.js:314:20)
at Duplexify.EventEmitter.emit (domain.js:548:15)
at PassThrough.emit (events.js:314:20)
at PassThrough.EventEmitter.emit (domain.js:548:15)
at onResponse (node_modules/retry-request/index.js:208:19)
at PassThrough.<anonymous> (node_modules/retry-request/index.js:155:11)
at PassThrough.emit (events.js:326:22)
at PassThrough.EventEmitter.emit (domain.js:548:15)
at node_modules/teeny-request/build/src/index.js:184:27
at processTicksAndRejections (internal/process/task_queues.js:93:5)
错误消息是一个大结构:
{
code: 404,
errors: [],
response: <ref *1> PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: false,
ended: true,
endEmitted: true,
reading: false,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
destroyed: true,
errored: null,
closed: true,
closeEmitted: true,
defaultEncoding: 'utf8',
awaitDrainWriters: Set(0) {},
multiAwaitDrain: true,
readingMore: false,
decoder: null,
encoding: null,
[Symbol(kPaused)]: true
},
_events: [Object: null prototype] {
prefinish: [Function: prefinish],
error: [Array],
close: [Array],
end: [Function: onend],
finish: [Function: onfinish]
},
_eventsCount: 5,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: true,
ended: true,
finished: true,
destroyed: true,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
prefinished: true,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: true
},
allowHalfOpen: true,
statusCode: 404,
statusMessage: 'Not Found',
request: {
agent: false,
headers: [Object],
href: 'https://storage.googleapis.com/storage/v1/b/MY-BUCKETNAME/o/MY-FILENAME?alt=media'
},
body: [Circular *1],
headers: {
'alt-svc': 'h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"',
'cache-control': 'private, max-age=0',
connection: 'close',
'content-length': '55',
'content-type': 'text/html; charset=UTF-8',
date: 'Tue, 23 Mar 2021 08:08:50 GMT',
expires: 'Tue, 23 Mar 2021 08:08:50 GMT',
server: 'UploadServer',
vary: 'Origin, X-Origin',
'x-guploader-uploadid': 'ABg5-Uz0P1kWSLFABXOpJ_mbQY5-4wEnMekQduBli1S4aYDWoIgqVKG1M5zlZ_ePd0iJDlzCl_ThYvmFpvcXpgwCcnN993kZog'
},
toJSON: [Function: toJSON],
[Symbol(kCapture)]: false,
[Symbol(kTransformState)]: {
afterTransform: [Function: bound afterTransform],
needTransform: false,
transforming: false,
writecb: null,
writechunk: null,
writeencoding: 'buffer'
}
},
domainEmitter: PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: false,
endEmitted: false,
reading: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: true,
emitClose: true,
autoDestroy: true,
destroyed: true,
errored: [Circular *2],
closed: true,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
prefinish: [Function: prefinish],
reading: [Function: makeRequest],
data: [Function (anonymous)],
end: [Function (anonymous)]
},
_eventsCount: 4,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: true,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
prefinished: false,
errorEmitted: true,
emitClose: true,
autoDestroy: true,
errored: [Circular *2],
closed: true
},
allowHalfOpen: true,
_read: [Function: bound ],
_write: [Function (anonymous)],
[Symbol(kCapture)]: false,
[Symbol(kTransformState)]: {
afterTransform: [Function: bound afterTransform],
needTransform: true,
transforming: false,
writecb: null,
writechunk: null,
writeencoding: null
}
},
domainThrown: false
}
您是否使用云CDN或任何第三方CDN?
询问原因有二:
云存储也与第三方CDN兼容
来源
为了在向用户交付内容时获得最佳性能,我们建议将云存储与云CDN结合使用。
来源
我建议首先看看您是否已经有任何CDN,这些CDN可能会影响对象缓存,从而导致您提到的延迟。
如果不是这样,我建议使用云CDN作为文档状态,与云存储相结合,它可以提供最佳性能。除了可能带来的优化性能外,云CDN还具有一些您可能会感兴趣的缓存设置。
最后,您提到了在HTTP请求中使用no store
标志,但请注意以下几点:
注意:Cache-Control 也是您可以在对象的 HTTP 请求中指定的标头;但是,Cloud Storage 会忽略此标头并根据存储的元数据值设置响应 Cache-Control 标头。
来源
google cloud bucket中的结果将具有正确的video/mp4 mimetype(这是由浏览器决定的),但仍然无法在浏览器上查看。 编辑: 我也尝试过使用chrome扩展名“Postman”在收到一个可恢复的上传链接后上传一个文件,但它的属性在上传到GCS时也会丢失,所以它似乎与将文件上传到GCS时涉及的JS端无关。
我应该做什么才能成功上传图片?任何帮助都将不胜感激。 非常感谢。
我们一直在使用服务,在(AWS)中,我们意外删除了一个目录,因此我们认为它应该在中,但是经过查看,尽管处于打开状态,但它并不存在。
我试图在vue js中构建镜像上传器,我希望它可以恢复上传,我从浏览器直接将请求发送到云存储服务器(例如,不使用php作为发送上传请求的中间件) 但是文档说我必须有访问令牌才能获取会话url,我稍后将使用它来上传图像,如何使用JavaScript获取此访问令牌,谷歌云没有javascript库,但在我不能用于浏览器使用的节点js中 邮递https://www.googleapis.com/uplo
追踪下面。 相关的Python片段: 最终触发(从ssl库): 溢出错误:字符串长度超过2147483647字节 我想我缺少一些特殊的配置选项? 这可能与这名1.5岁的年轻人有关,显然他还没有解决问题:https://github.com/googledatalab/datalab/issues/784. 谢谢你的帮助! 完整跟踪: [File”/usr/src/app/gcloud/downlo
我想按照官方文档中提供的示例将一个文件上传到Google云存储 然而,我得到了一个错误: 线程“main”com.google.cloud.storage.StorageException中的异常:获取服务帐户的访问令牌时出错:400个错误请求{“错误”:“无效的授予”、“错误描述”:“无效的JWT:令牌必须是短期令牌(60分钟)并且在合理的时间范围内。请检查JWT声明中的iat和exp值。”位于