通过最近的学习发现,那些技术书籍未必都那么严谨,有些或多或少都有些问题。特别是书上的示例代码,最好都理解后自己再写一遍。说不定就能碰到书上没有说到的问题。
我今天看到了http
模块。书上有一个关于Ajax请求数据的例子,我看完之后也写了一遍,却发现书上挖了个大坑,或者说书上说的并不详细。
我写的代码是这样的:
- 网页代码:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta charset="utf-8">
<script type="text/javascript">
function clickHandler(){
let xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost:2000/", true);
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
document.getElementById('test').innerHTML = xhr.responseText;
console.log(xhr.responseText);
}
}
}
xhr.send();
}
</script>
</head>
<body>
<button onclick="clickHandler()">Ajax获取数据</button>
<div id="test"></div>
</body>
</html>
2.服务器端代码
let http = require('http');
let httpServer = http.createServer();
httpServer.on('request', (req,res)=>{
console.log(req.headers);
res.writeHead(200,{'Content-Type': "text/plain", 'Access-Control-Allow-Origin': 'http://localhost'});
res.write('Hello World');
res.end();
});
//监听2000端口
httpServer.listen(2000);
httpServer.on('listening',()=>{
console.log('服务器开始监听');
});
但是当我打开页面,点击网页上的按钮时。浏览器的控制台却打印出了这样的错误。
错误内容是
test.html:1 Access to XMLHttpRequest at ‘http://localhost:2000/’ from origin ‘null’ has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header has a value ‘http://localhost’ that is not equal to the supplied origin.
这个时候我非常奇怪,重新看书,觉得自己写的代码与书上的代码没有什么逻辑上的差异啊,怎么会出错?
由于报错内容有关CORS,我就去查了一下有关信息。我得知将响应头的Access-Control-Allow-Origin
属性的值设为*
之后将会允许所有外域访问。于是我抱着试一试的心态把代码修改成下面的样子
let http = require('http');
let httpServer = http.createServer();
httpServer.on('request', (req,res)=>{
console.log(req.headers);
res.writeHead(200,{'Content-Type': "text/plain", 'Access-Control-Allow-Origin': '*'});
res.write('Hello World');
res.end();
});
//监听2000端口
httpServer.listen(2000);
httpServer.on('listening',()=>{
console.log('服务器开始监听');
});
结果还真的是不报错了,并且成功的返回了数据。
这也证实了我的猜想和错误提示–问题的确与跨域请求有关。
这个时候,我又注意到错误信息里的一句话 “from origin ‘null’ has been blocked by CORS policy”。
origin
怎么会为null
呢?
而我一开始为响应头的Access-Control-Allow-Origin
属性设置的是http://localhost
。难道我把Access-Control-Allow-Origin
属性设置为"null"
也可以?
let http = require('http');
let httpServer = http.createServer();
httpServer.on('request', (req,res)=>{
console.log(req.headers);
res.writeHead(200,{'Content-Type': "text/plain", 'Access-Control-Allow-Origin': 'null'});
res.write('Hello World');
res.end();
});
//监听2000端口
httpServer.listen(2000);
httpServer.on('listening',()=>{
console.log('服务器开始监听');
});
果然,把Access-Control-Allow-Origin
属性设置为"null"
之后,网页的Ajax操作也一样是正常的。那么现在的问题就是,为什么页面发出的请求头的origin
属性会是null
?
我查了MDN中关于请求头中origin
属性的描述
origin 参数的值为源站 URI。它不包含任何路径信息,只是服务器名称。
然后又看到了stackoverflow上的一个回答里的一句话
However, file:// URLs produce a null Origin which can’t be authorized via echo-back.
原来是这样,我所写的那个页面是直接在本地打开,并不是从哪个服务器获得,于是也就不存在所谓的“源站”。所以origin
属性就会是'null'
。
换句话说,如果你的页面的URL是以 “file://” 开头的,那么这个页面的所发出的请求头的origin
属性的值就是'null'
。