异步加载图片
练习 Promise,现在想应用 Promise 异步加载 vue 官网中的一张图:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function loadImg(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
resolve(xhr.response)
} else {
reject(Error('image didn\'t load successfully; error code: ' + xhr.statusText))
}
}
}
xhr.send();
})
}
let body = document.querySelector('body');
let myImage = new Image();
loadImg('https://cn.vuejs.org/images/data.png').then((response) => {
let myImageUrl = window.URL.createObjectURL(response)
myImage.src = myImageUrl;
body.appendChild(myImage);
}, (error) => {
console.log(error);
})
</script>
</body>
</html>
图片的加载没有问题
响应头和请求头如下:
这里有一些有意思的地方:
- 请求头中有 if-modified-since,状态码中有 304(not modified),传输为已缓存,服务器告诉浏览器不用再请求资源,直接用本地的就行。这是因为我之前以及请求过这张图,晴空缓存后重新请求,状态码就是 200,传输就是 20.81 KB(图片大小)+ 1.402 KB(响应头大小) = 22.21 KB
- 请求头中的 Host 为
cn.vuejs.org
,Referer 为http://127.0.0.1:5500
,这是什么意思? - 请求头中有
Origin: http://127.0.0.1:5500
响应头中有access-control-allow-origin: *
,这里已经用 CORS 解决了跨域问题,但是我并没有在 ajax 代码中写,这应该是它们服务器干的事
请求 vue 官网下的图片没问题,试了一下,请求 webpack 官网的图片也没有问题,那请求微博的图片呢?
现在把 loadImg 中的 URL 改成一张微博图片的 url:
https://wx4.sinaimg.cn/mw690/6967c9b3ly1gp5dkj2i8xj20u01hc4qr.jpg
然后:
图片并没有加载出来,并且控制台有报错
换成 chrome 也是一样的
下面我尝试用 CORS 解决这个跨域问题:
首先,我想通过
xhr.setRequestHeader()
修改请求报文的 Origin 属性,伪装一个请求报文,试了半天,Origin 并没有发生变化,一查 MDN,说安全起见,有些请求头的值只能由user agent设置,其中就有 Origin。所以伪装这方法不行。-
MDN 说的是:
如果服务器在您的控制之下,请将请求站点的 Origin 添加到允许访问的域集,方法是将其添加到
Access-Control-Allow-Origin
头的值。可是现在服务器不在我的控制之下啊!
看来这个问题我是解决不了了,新浪不允许跨域访问它们加的资源,就是访问不了。
为了验证是新浪服务器拒绝了我的访问,写了个这个:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img src="https://wx4.sinaimg.cn/orj360/6967c9b3ly1gp5dkj2i8xj20u01hc4qr.jpg" alt="">
<img src="https://cn.vuejs.org/images/data.png" alt="">
</body>
</html>
效果如下,新浪的图加载不出来,vue 的图可以。
注意状态码是 403,状态码 403 Forbidden 代表客户端错误,指的是服务器端有能力处理该请求,但是拒绝授权访问。(MDN)
差点忘了我是来干嘛的,我是来学 Promise 的。
这个 Promise 的应用,将已经是异步请求的 ajax 又封装在了 Promise 里,感觉有点多余,实际上,只要在 xhr.readyState === 4 && xhr.status === 200
的时候,把 xhr.response
传给图片的 URL 就行,没有必要再把它封装到 Promise 中的 then 去的,不过,这样写到 Promise.then 中去可能看起来更简洁吧。