写在前面
- 浏览器可以发请求,收响应(地址栏)
- 浏览器把这个功能暴露给js开发者,让开发者用js来控制浏览器发请求,收响应
- 于是浏览器在window上加了一个XMLHttpRequest函数,用这个构造函数可以构造出一个XMLHttpRequest对象,JS用这个XMLHttpRequest对象实现发请求和收响应(AJAX)
- 这次我们用nodejs模拟服务器,AJAX内容不包括服务端的js代码
服务端小知识
- 以nodejs为例,我们把响应内容放在
repose.write()里 - 但我们平常为什么不在
repose.write()写东西呢 - 我们把
fs.readFileSync('public/index.html')写在write里相当于把整个文件夹当成字符串写在write中,和直接写是一样的(因为直接写也写在双引号当中的) - 注意HTML文件中的引用
script和link中路径要与nodejs中的path一致才行
AJAX概念
AJAX 这个词就成为 JavaScript 脚本发起 HTTP 通信的代名词
加载css
加载css的两种方式
- 利用html中的link和serve.js中的path相结合,加载出css
- 利用AJAX加载css
- AJAX四个步骤
- 创建 XMLHttpRequest 实例,使用它的open方法
- 发出 HTTP 请求 ,监听它的成功失败
- 接收服务器传回的数据
- 更新网页数据
AJAX获取文件
getCss.onclick = () => {
const request = new XMLHttpRequest();
request.open("GET", "/public/style.css");
request.onload = () => {
console.log("success");
};
request.onerror = () => {
console.log("fail");
};
request.send();
};
- 此时用js构造了一个HTTP请求,请求/public/style.css文件
- /public/style.css的路径是与服务端的路径是一致的很好理解,因为请求就是送往服务端的,请求的路径是服务端的一个路由(if else)才有意义
- 对比link方式,在HTML中发送请求,响应发送给浏览器,浏览器插到link,src位置
- 而利用AJAX方式浏览器请求成功得到了响应内容,却没有放置它(onload里只是打了一个success没有进一步行动),响应发送给浏览器
request.onload = () => {
console.log("success");
const style = document.createElement('style')
style.innerHTML = request.response
document.head.appendChild(style)
};
- onload中这样写,请求成功才有意义
- 所有的请求浏览器都会得到一个文件,区别在于普通方法浏览器会直接插到src位置,AJAX还需要对
new XMLHttpRequest().open("GET","/public/2.js").response
即浏览器得到的文件,进行操作 - 普通方法:刚开始下载HTML,看到link发起请求,服务端得到请求,返回响应,浏览器接受响应,下载CSS,浏览器得到css文件,插到link处,开始解析
- AJAX:下载HTML,下载js代码看到
new XMLHttpRequest()发起请求,服务器看到请求返回响应,浏览器接受响应,浏览器得到css文件,并没有插入到相应位置,待解析 - AJAX还需对得到的文件手动插入,比如js代码写在加载完成时插入
onload&onerror
- 他俩不能很好地匹配AJAX,比如输错路径返回404不是error
XMLHttpRequest.onreadystatechange更专业是个回调函数当浏览器察觉到变化时浏览器才会调用,所以可以写在send()前面,却判断readyState是否等于4- XMLHttpRequest.readyState 属性返回一个 XMLHttpRequest 代理当前所处的状态。一个 XHR 代理总是处于下列状态中的一个:
| 值 | 状态 | 描述 |
|---|---|---|
| 0 | UNSENT | 代理被创建,但尚未调用 open() 方法。 |
| 1 | OPENED | open() 方法已经被调用。 |
| 2 | HEADERS_RECEIVED | send() 方法已经被调用,并且头部和状态已经可获得。 |
| 3 | LOADING | 下载中; responseText 属性已经包含部分数据。 |
| 4 | DONE | 下载操作已完成。 |
- 0:未初始化
- 1:open方法成功调用以后,请求等待发送
- 2:send() 方法已经被调用,服务器已经应答客户端的请求,请求已经发送
- 3:交互中。Http头信息已经接收,响应数据尚未接收。接受第一个响应信息出现时
- 4:完成。数据接收完成
- 上面顺序下来就是一个请求的一生
- 一边下载一边显示
XMLHttpRequest.onreadystatechange属性指向一个监听函数。readystatechange事件发生时(实例的readyState属性变化),就会执行这个属性。是一个回调函数,浏览器看到这一行代码是不会立即调用的
- 如果路径错误(404)readystatec仍会经历3,4阶段,即把失败下载完了
- 我们可以通过判断
new XMLHttpRequest().status,是否为404即可知道路径是否正确 - XMLHttpRequest.status属性返回一个整数,表示服务器回应的 HTTP 状态码。
- 那么结合起来两个if,外面判断readyState,里面判断status
request.onreadystatechange = () => {
//下载完成,但不知道是成功2xx还是失败4Xx 5xx
if ((request.readyState = 4)) {
if (request.status >= 200 && request.status < 300) {
//创建style标签
const style = document.createElement("style");
//填写style内容
style.innerHTML = request.response;
//插到头里面
document.head.appendChild(style);
} else {
alert("加载CSS失败");
}
}
};
区别
XMLHttpRequest.response属性表示服务器返回的数据体(即 HTTP 回应的 body 部分),它可能是任何数据类型,比如字符串、对象、二进制对象等等,具体的类型由XMLHttpRequest.responseType属性决定。默认为text即字符串,因为服务器write的就是字符串,正好innerHTML接口是接受字符串的XMLHttpRequest.responseXML属性返回从服务器接收到的 HTML 或 XML 文档对象,该属性为只读。如果本次请求没有成功,或者收到的数据不能被解析为 XML 或 HTML,该属性等于null。返回的是一个DOM对象XMLHttpRequest.responseXML该属性生效的前提是 HTTP回应的Content-Type头信息等于text/xml或application/xml。
总结
- http什么都可以请求,css,js,html,xml...记得设置正确content-type
- 我们用AJAX得到的还没有经过解析,得到CSS之后生成style标签,得到JS之后生成script标签,得到HTML之后使用innerHTML和DOM API,得到XML之后使用responseXML和DOM API不同类型的数据有不同类型的解析办法
- 注意:下载和加载是同时的,发送请求起接受响应,下载响应内容和显示是同时的
注意
- 有一点值得注意,我们在判断
request.readyState = 4``request.status >= 200时是为了让我们解析response - 我们在条件里做的就是为了解析