【发布时间】:2018-04-08 20:20:08
【问题描述】:
我正在摆弄 Google Cloud Storage。我创建了一个简单的 Python Flask 处理程序:
#!/usr/bin/env python3
import secrets
import flask
from flask_cors import CORS
from google.cloud import storage
app = flask.Flask(__name__)
CORS(app)
client = storage.Client()
bucket = client.get_bucket('<my-bucket>')
@app.route('/')
def get_upload_urls():
blob = bucket.blob('00000' + secrets.token_hex())
return flask.jsonify({
'url': blob.create_resumable_upload_session(),
})
if __name__ == '__main__':
app.run('0.0.0.0', 9999)
这伴随着一个非常简单的网络前端:
index.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1,width=device-width">
<title>Test</title>
</head>
<body>
<input id="input" type="file" />
<button id="button">Upload</button>
<script src="index.js"></script>
</body>
</html>
index.js:
const input = document.getElementById('input')
const button = document.getElementById('button')
button.addEventListener('click', async () => {
const [ body ] = input.files
const response = await fetch('http://localhost:9999')
const { url } = await response.json()
await fetch(url, {
method: 'PUT',
body,
})
})
这个前端允许我选择一个文件,然后使用 Python 后端创建的可恢复上传会话将其上传到 Google Cloud Storage。
问题在于它确实有效。我希望 PUT 请求失败,但事实并非如此。
选择文件并按下上传按钮后,控制台会记录以下错误:
index.html:1 加载失败 https://www.googleapis.com/upload/storage/v1/b//o?uploadType=resumable&upload_id=: 请求中不存在“Access-Control-Allow-Origin”标头 资源。因此不允许使用原点“http://localhost:3333” 使用权。如果不透明的响应满足您的需求,请设置请求的 模式为“no-cors”以获取禁用 CORS 的资源。
index.js:13 Uncaught (in promise) TypeError: Failed to fetch
async function (async)
button.addEventListener @ index.js:5
但是,PUT 请求已成功发出,文件显示在 Google Cloud Storage 中。我可以下载它,它似乎完全没问题。
尽管控制台出现 CORS 错误,为什么 PUT 请求没有失败?
编辑:
我只是在寻找解释,而不是解决方法——无论如何我都会正确配置 CORS。我只想知道为什么请求没有失败,为什么 fetch 会拒绝。
【问题讨论】:
-
你有没有试过在获取模式中使用模式
{mode: 'no-cors'} -
CORS 防止人们从其他来源“借用”资源,远程服务器如何处理发送到它的数据显然掌握在服务器手中
-
我能想象的唯一解释:(1)服务器发送回正确的 CORS 标头(包括 Access-Control-Allow-Origin 标头)以响应 OPTIONS 预检浏览器(自动在其own) 在尝试您的 PUT 之前执行,然后 (2) 因为预检成功,浏览器继续并从您的代码发送 PUT,然后 (3) 服务器接收 PUT 并成功处理它,但随后 (4)服务器为 PUT 发回的响应没有 Access-Control-Allow-Origin 标头,因此 (5) 您的浏览器阻止您的前端代码访问该响应
-
您可能需要考虑更新问题以粘贴在前端代码运行时显示在浏览器 devtools 的“网络”窗格中的请求和响应的详细信息 — 包括响应,以及请求和响应的所有标头。我说 requests 和 responses 复数是因为,由于您正在发出跨域 PUT 请求,您的浏览器肯定会在发送 PUT 之前发送预检 OPTIONS要求。因此,除了 PUT 的详细信息之外,您还想查看 OPTIONS 的详细信息
-
你在这里做两个
fetches,对吧?所以大概第一个(fetch('http://localhost:9999'))失败并导致控制台条目,另一个,你的实际 PUT 请求,成功......
标签: javascript cors google-cloud-storage fetch-api