javascript - 同源提取导致空比较(HTTP CORS)
问题描述
一个简单的同源fetch("fetch.xml")
在此处失败并显示控制台错误消息
CORS 策略已阻止从源“null”获取“http://127.0.0.1:8000/fetch.xml”的访问权限:“Access-Control-Allow-Origin”标头的值为“http://” 127.0.0.1:8000' 不等于提供的原点。让服务器发送带有有效值的标头,或者,如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。
相应的网络标头是
General
Request URL: http://127.0.0.1:8000/fetch.xml
Referrer Policy: origin
Response Headers
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Origin: http://127.0.0.1:8000
Access-Control-Max-Age: 86400
Content-Security-Policy: sandbox allow-scripts
Content-Type: text/xml
Date: Sun, 16 Aug 2020 06:20:43 GMT
Referrer-Policy: origin
Server: SimpleHTTP/0.6 Python/3.8.5
Request Headers
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
DNT: 1
Host: 127.0.0.1:8000
Origin: null
Pragma: no-cache
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
如您所见,浏览器(此处为 Chrome)显示 Origin = null,尽管来源是同一个来源。我也可以使用真实域而不是 ip 地址来重现它,根据浏览器,提取的来源始终为空。
如果我将 fetch 语句更改fetch("fetch.xml", { mode: "same-origin" })
为浏览器仍然假定 null 是原点,但错误消息更改为
Fetch API 无法加载http://127.0.0.1:8000/fetch.xml。请求模式为“同源”,但 URL 的来源与请求来源 null 不同。
如何让浏览器使用正确的来源而不是 fetch 语句为空?如您所见,我使用了推荐人策略。我不希望Access-Control-Allow-Origin包含 null 或 *,因为这似乎太开放了(基本上禁用了 CORS)。
备注:我没有通过file://
URL 访问文件!这是一个真正的 Web 服务器,并且来源仍然为空!所以这个问题与重复的stackoverflow链接到的不同。
最小复制示例
如果您想快速测试它,简单的服务器包括所有内容(只需使用 python3 运行它):
#!/usr/bin/env python3
from http.server import HTTPServer, HTTPStatus, SimpleHTTPRequestHandler, test
import sys
from urllib.parse import urlparse
import os
class TestRequestHandler (SimpleHTTPRequestHandler):
def do_GET(self):
"""Serve a GET request."""
url = urlparse(self.path)
if url.path == '/' or url.path == '/index.html': # index.html
f = self.send_head('text/html')
self.wfile.write('''<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="control.js"></script>
</head>
<body>
</body>
</html>'''.encode('utf-8'))
elif url.path == '/control.js': # control.js will try to fetch the fetch.xml
f = self.send_head('application/javascript')
self.wfile.write('''function init() {
fetch("fetch.xml", { mode: "same-origin" }).then(r => r.text()).then(t => console.log(t));
}
window.addEventListener("load", init);'''.encode('utf-8'))
elif url.path == '/fetch.xml': # fetch.xml
f = self.send_head('text/xml')
self.wfile.write('''<?xml version="1.0" encoding="UTF-8"?>
<root>
<test>Hi</test>
</root>'''.encode('utf-8'))
def send_head(self, ctype):
self.send_response(HTTPStatus.OK)
self.send_header('Content-Type', ctype)
self.send_header('Access-Control-Allow-Origin', 'http://127.0.0.1:8000')
self.send_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
self.send_header('Access-Control-Max-Age', 86400)
self.send_header('Referrer-Policy', 'origin')
self.send_header('Content-Security-Policy', 'sandbox allow-scripts')
SimpleHTTPRequestHandler.end_headers(self)
if __name__ == '__main__':
test(TestRequestHandler, HTTPServer, port=int(sys.argv[1]) if len(sys.argv) > 1 else 8000)
如果您更喜欢将其放在您自己的服务器上,并使用不同的文件:
索引.html
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="control.js"></script>
</head>
<body>
</body>
</html>
控制.js
function init() {
fetch("fetch.xml", { mode: "same-origin" }).then(r => r.text()).then(t => console.log(t));
}
window.addEventListener("load", init);
获取.xml
<?xml version="1.0" encoding="UTF-8"?>
<root><test>Hello</test></root>
服务器应设置为发送以下标头(调整 ip/域):
Access-Control-Allow-Origin: http://127.0.0.1:8000
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 86400
Referrer-Policy: origin
Content-Security-Policy: sandbox allow-scripts
解决方案
这是你的问题:
Content-Security-Policy: sandbox allow-scripts
请参阅文档。
您没有启用此指令:
允许同源
允许将内容视为来自其正常来源。如果未使用此关键字,则嵌入的内容将被视为来自唯一来源。
......所以http://localhost:8000/
和http://localhost:8000/fetch.xml
被视为不同的,独特的起源。
推荐阅读
- javascript - html表单行上两个输入表元素值的乘法不起作用(Google Webapp)
- angular - highchart 地图:mapbubble 为同一国家/地区的气泡系列设置自定义 x、y 坐标
- c# - 检测现代待机中的电源状态变化
- r - 使用函数内的逻辑条件访问全局向量分量
- reactjs - 找不到 React 模块?
- jquery - 我想从我通过 ajax 函数提供的 id 中获取订单号,但没有成功显示值:function(response)
- c++ - 为什么这个程序 35% 被接受,但其余的是运行时错误?
- python - 我在用 bs4 抓取网页时遇到问题
- .net - 将 MERGE 语句的更新列审计为不同表中的行
- python-3.x - 随机选择文件中的两个位置并交换单词