Ajax笔记

Day25 Ajax 课堂笔记

1 原生 Ajax – 使用 xhr 对象

1.1 基本使用流程

// 第一步 创建 xhr 对象 XMLHttpRequest
var xhr = new XMLHttpRequest();

// 第二步 监听 xhr 对象发起的 http 请求状态
// readystate 值发生变化,就会触发,整个请求过程共计触发 4 次
/*
xhr.onreadystatechange = function() {
    // 当响应内容接收完毕之后
    if (xhr.readyState === 4) {
        // 获取响应体的内容
        console.log(xhr.responseText);
    }
};
*/
// 当响应完成后(已经接收完所有响应内容)触发 load 事件 -- 可以代替 readystatechagne 事件
xhr.onload = function() {
    console.log(xhr.responseText);
    box.innerHTML = xhr.responseText;
}

// 第三步 进行初始化,为发送http请求做准备 指定请求方式和URL
xhr.open('GET', 'http://localhost:8080/getData');

// 第四步 发送请求
xhr.send();
readyState 的值:
0	初始值
1   open()方法已经调用,请求初始化完毕
2   send()方法已经调用,请求已经发出,并且开始接收响应行和响应头
3   已经开始接收响应体
4   所有的响应内容接收完毕

1.2 发起请求携带数据

1.2.1 GET 方式通过 URL 携带数据

GET 方式没有请求体,只能通过 URL 携带数据

// 请求初始化 可以将数据拼接到url中
xhr.open('GET', '/addData?a=100&b=200');
// 发送请求 GET方式没有请求体,send()不需要参数
xhr.send();

1.2.2 POST 方式通过请求体携带数据

// 请求初始化 POST 也可以通过 URL 携带数据
xhr.open('POST', '/addData?type=100');

// 在初始化之后请求之前,通过设置请求头的 Content-type 字段,设置请求体的内容类型
xhr.setRequestHeader('Content-type', 'text/plain');

// 发送请求 POST 方式可以指定请求体
xhr.send(msg);

1.2.3 请求体内容类型

text/plain
1. 默认的请求体类型,如果不设置请求头字段 Content-type,默认就是该种类型
2. 请求体只要是字符串就可以,后端不会做任何处理

application/x-www-form-urlencoded

1. 需要设置 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
2. 要求请求体是查询字符串,如 a=100&b=200
3. 点击提交按钮提交表单(非Ajax),如果 Method 是 Post,默认请求体内容就是 x-www-form-urlencoded

application/json

1. 设置设置 xhr.setRequestHeader('Content-type', 'application/json');
2. 要求请求体是 json 格式的字符串

1.2.4 其他请求方式

无需发送请求体: GET、HEAD

可以添加请求体: POST、PUT、DELETE、OPTIONS、PATCH

1.2.5 发送请求携带数据案例总结

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>发送请求携带数据</title>
</head>
<body>
    <h1>发送请求携带数据</h1>
    <hr>
   
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username" id="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="pwd" id="pwd"></td>
            
        </tr>
        <tr>
            <td></td>
            <td>
                <button id="btn1">GET方式提交</button>
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <br>
                <button id="btn2">POST方式提交 - plain</button> <br>
                <button id="btn3">POST方式提交 - urlencoded</button> <br>
                <button id="btn4">POST方式提交 - json</button> <br>
                <br>
                <button id="btn5">PUT方式提交</button> <br>
            </td>
        </tr>
    
    </form>

    <script>
        // 获取元素
        var userInp = document.querySelector('#username');
        var pwdInp = document.querySelector('#pwd');

        // 创建 xhr 对象
        var xhr = new XMLHttpRequest();

        // 监听响应结束的事件
        xhr.onload = function() {
            alert(xhr.responseText);
        };

        // 1. 点击按钮 发起 GET 请求, GET方式如何携带数据
        var btn1 = document.querySelector('#btn1');
        btn1.onclick = function(){
            // 将表单的数据拼接到查询字符串中
            var msg = `username=${userInp.value}&password=${pwdInp.value}`;

            // 请求初始化 可以将数据拼接到url中
            xhr.open('GET', '/addData?' + msg);
            // 发送请求 GET方式没有请求体,send()不需要参数
            xhr.send();
        }
   
        // 2. 点击按钮 发起 POST 请求
        var btn2 = document.querySelector('#btn2');
        btn2.onclick = function() {
            // 将表单的数据拼接到查询字符串中
            var msg = `username=${userInp.value}&password=${pwdInp.value}`;
            // 请求初始化
            xhr.open('POST', '/addData?type=100');
            // 发送请求
            xhr.send(msg);
        }
   
        // 3. 点击按钮 发起 POST 请求 指定请求体内容类型 application/x-www-form-urlencoded
        var btn3= document.querySelector('#btn3');
        btn3.onclick = function(){
            // 将表单的数据拼接到查询字符串中
            var msg = `username=${userInp.value}&password=${pwdInp.value}`;
            // 请求初始化
            xhr.open('POST', '/addData?type=200');
            // 在请求初始化之后,发送请求之前,设置请求头
            xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');   
            // 发送请求
            xhr.send(msg);
        }
  
        // 4. 点击按钮 发起 POST 请求, 指定请求体内容类型是 application/json
        var btn4= document.querySelector('#btn4');
        btn4.onclick = function() {
            // 定义对象
            var obj = {
                username: userInp.value,
                password: pwdInp.value
            }
            // 请求初始化
            xhr.open('POST', '/addData?type=300');
            // 在请求初始化之后,发送请求之前,设置请求头
            xhr.setRequestHeader('Content-type', 'application/json');   
            // 发送请求 请求体要求是 json 格式的字符串
            xhr.send(JSON.stringify(obj));
        };


        // 5. 点击按钮 发起 PUT请求, 指定请求体内容类型是 application/json
        var btn5= document.querySelector('#btn5');
        btn5.onclick = function() {
            // 定义对象
            var obj = {
                username: userInp.value,
                password: pwdInp.value
            }
            // 请求初始化
            xhr.open('PUT', '/addData?type=400');
            // 在请求初始化之后,发送请求之前,设置请求头
            xhr.setRequestHeader('Content-type', 'application/json');   
            // 发送请求 请求体要求是 json 格式的字符串
            xhr.send(JSON.stringify(obj));
        };
  </script>

</body>
</html>

1.3 文件上传

① 使用 FormData 对象实现文件上传

1. 请求体(send()的方法的参数)除了是字符串,也可以是 formData 对象
2. 如果请求体是 FormData 对象,浏览器会自动设置请求头字段 Content-type 为 multipart/form-data
// 方式一 创建 空的 FormData,再添加数据,可以添加文件数据或者字符串数据
var fd = new FormData();
fd.append('message', msgInput.value);
fd.append('avator', avatorInput.files[0]);
fd.append('content', 'hello ajax');

// 方拾二 根据表单元素创建 FormData 会包含表单中所有的信息
var fd = new FormData(uploadForm);

② FormData 对象的方法

append()
set()
delete()
get()
getAll()

上传文件案例

<!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>Ajax 上传文件</title>
</head>
<body>
    <h1>Ajax 上传文件</h1>
    <form id="uploadForm" onsubmit="return false">
        <input type="text" placeholder="留言" name="msg" id="msg"> <br><br>
        <input type="file" name="avator" id="avator"><br><br>
        <button id="btn">上传</button>
    </form>

    <script>
        // 获取相关元素
        var uploadForm = document.querySelector('#uploadForm');
        var msgInput = document.querySelector('#msg');
        var avatorInput = document.querySelector('#avator');
        var btn = document.querySelector('#btn');


        // 创建 xhr 对象
        var xhr = new XMLHttpRequest();

        // 设置响应成功之后的回调
        xhr.onload = function() {
            alert(xhr.responseText);
        }

        // 点击按钮 执行上传
        btn.onclick = function() {
            // 创建 空的 FormData,再添加数据
            // var fd = new FormData();
            // fd.append('message', msgInput.value);
            // fd.append('avator', avatorInput.files[0]);
            // fd.append('content', 'hello ajax');

            // 根据表单元素创建 FormData
            var fd = new FormData(uploadForm);
            
            // 请示初始化
            xhr.open('POST', '/upload')
            // 发送请求
            xhr.send(fd);
        };

    </script>
</body>
</html>

1.4 读取响应报文

// 响应行
xhr.status;			// 响应状态码
xhr.statusText;		// 响应状态描述

// 响应头
xhr.getResponseHeader('响应头字段');		// 获取指定字段的响应头的信息
xhr.getAllResponseHeaders();		   // 获取所有的响应头信息

// 响应体
xhr.responseText;		// 获取响应体体符串
xhr.response;			// 获取响应体字符串,如果响应体是特殊格式的字符串,会进行处理,前提是设置xhr.responseType = ' ';

1.5 响应 json 格式的数据

1.5.1 服务端设置

设置响应头,告知浏览器响应体的内容类型是 json 格式

Content-type: application/json;charset=utf-8

1.5.2 客户端处理接收到的 json 数据

① 方式一 使用 JSON.parse
// 监听响应结束的回调函数、
xhr.onload = function() {
    // 将响应体中 json 格式的字符串处理成对象
    var resData = JSON.parse(xhr.responseText);
}
② 方式二 设置 xhr.responseType 属性 ,通过 xhr.response获取 (xhr2 方案)
xhr.responseType = 'json';
xhr.onload = function() {
    xhr.response;		// 直接得到处理好的对象
}

1.5.3 响应json数据案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>请求json数据</title>
    <style>
        #box p {
            width: 600px;
            padding: 10px;
            border: 2px dashed #ccc;
        }
    </style>
</head>
<body>
    <h1>响应 json 格式的数据</h1>
    <button id="btn1">请求数据 第一种处理josn的方式</button>
    <button id="btn2">请求数据 第二种处理json的方式</button>
    <hr>
    <div id="box">
    </div>

    <script>
        // 获取相关元素
        var btn1 = document.querySelector('#btn1');
        var btn2 = document.querySelector('#btn2');
        var box = document.querySelector('#box');

        // 创建 xhr 对象
        var xhr = new XMLHttpRequest();

        // 点击第一个按钮 自行处理响应体内容
        btn1.onclick = function() {
            // 请求初始化
            xhr.open('GET', '/getUsers');

            // 发送请求
            xhr.send();

            // 监听响应结束的回调函数、
            xhr.onload = function() {
                // 将响应体中 json 格式的字符串处理成对象
                var resData = JSON.parse(xhr.responseText);
                
                // 遍历数组
                resData.forEach(function(item, index){
                    // 创建元素
                    var pEle = document.createElement('p');
                    pEle.innerHTML = `序号:${index},姓名:${item.name},年龄:${item.age},地址:${item.address}`;
                    // 添加元素
                    box.appendChild(pEle);
                })
            }
        }


        // 点击第二个按钮 
        btn2.onclick = function() {
            // 请求初始化
            xhr.open('GET', '/getUsers');

            // 发送请求
            xhr.send();

            // 设置响应体类型
            xhr.responseType = 'json';

            // 监听响应结束的回调函数、
            xhr.onload = function() {
                var resData = xhr.response;
                
                // // 遍历数组
                resData.forEach(function(item, index){
                    // 创建元素
                    var pEle = document.createElement('p');
                    pEle.innerHTML = `序号:${index},姓名:${item.name},年龄:${item.age},地址:${item.address}`;
                    // 添加元素
                    box.appendChild(pEle);
                })
            }
        }
    </script>
</body>
</html>

1.6 响应超时

1.6.1 方案一 兼容方案

// 发送请求
xhr.send();

// 发送请求之后,设置单次定时,如果时间到了还没有接收到响应,中断请求
setTimeout(function(){
    // 判断如果没有响应结束
    if (xhr.readyState !== 4) {
        xhr.abort();  // 中断请求
        alert('请求超时!');
    }
}, 5000);

1.6.2 案二 XHR2 方案

 // 监听响应超时的事件
xhr.ontimeout = function(){
    alert('响应超时!');
}

// 请求初始话
xhr.open('GET', '/getInfo');

// 发送请求之前设置超时时间
xhr.timeout = 5000;

// 发送
xhr.send();

1.6 HTTP 进度事件

1.6.1 进度相关事件

readystatechange	触发至少 4 次
loadstart			开始请求的时候触发,此时 readyState 的值是 1
load				响应结束的时候触发,此时 readyState 的值是 4,请求成功触发
error				请求失败触发,应用层面的错误也算是请求成功(如 404错误),只有网络错误才算请求失败
loadend				响应结束之后触发,不论请求是否成功都会触发
progress			开始接收响应内容之后,被触发多次,该事件的回调函数可以获取一个 progressEvent 对象

相关事件的触发顺序: loadstart、progress(可能会触发多次)、 load/error、loadend

1.6.2 ProgressEvent 事件对象

progress 事件的回调函数可以获取一个 progressEvent 对象,该对象有如下属性:

loaded		表示当前已经下载的字节数
total		表示响应内容的总长度

1.7 异步请求和同步请求

两者区别:

1. 异步请求,请求发送之后,其他同步操作继续执行; 当获取响应之后触发回调函数,回调函数进入回调队列等待主线程空闲执行
2. 同步请求,请求发送之后,其他的同步操作必须等到,响应结束之后才能继续执行

如何发送同步请求:

open() 方法的第三个参数是布尔值,true 表示异步请求,false 表示同步请求,默认值是 true。

1.8 XMLHttpRequest 对象

① XHR 对象概述

1)XMLHttpRequest 对象简称 XHR 对象。

2)XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。

3)XMLHttpRequest 可以同步或异步地返回 Web 服务器的响应,并且能够以文本或者一个 DOM 文档的形式返回内容。

4)尽管名为 XMLHttpRequest,它并不限于和 XML 文档一起使用,它可以接收任何形式的文本文档。

② 创建 XHR 对象

使用构造函数 XMLHttpRequest 就可以创建一个 XHR 对象。

let xhr = new XMLHttpRequest()

注意:在古老的 IE 浏览器中(如:IE6),需要使用其他方式来创建 XHR 对象。

// IE5、IE6
let xhr = new ActiveXObject("Microsoft.XMLHTTP");

③ XHR 对象的属性

属性名 含义
readyState 返回一个数字,表示请求的状态:
0 – UNSET – XHR对象已创建或已被 abort() 方法重置。
1 – OPENDED – open() 方法已经被调用。
2 – HEADERS_RECEIVED – send() 方法已经被调用,并且响应头和响应状态已经可获得。
3 – LOADING – 下载中, responseText 属性已经包含部分数据。
4 – DONE – 所有响应数据接收完毕。
status 响应状态码,如 404、200 等。
statusText 响应状态码的文本描述,如 200 对应的是 “OK”。
responseXML 接收格式为 XML 的响应数据,返回一个 document 对象。
responseText 获取响应文本,返回一个字符串。
responseType 用于设置响应内容的类型 xhr2
response 返回的类型取决于 responseType 的设置。 xhr2
timeout 设置超时时间。xhr2

④ XHR 对象的方法

方法名 含义
open() 初始化 HTTP 请求,用来指定请求方式和 URL。 xhr.open(method, url, [async], [user], [password])
send() 发送 HTTP 请求,参数可以设置请求体,没有请求体无需设置参数。
setRequestHeader() 设置 HTTP 请求头的值。必须在 open() 之后、send() 之前调用。
abort() 如果请求已被发出,则立刻中止请求。
getAllResponseHeaders() 以字符串形式返回所有的响应头。
getResponseHeader() 返回指定的响应头。

⑤ XHR 对象的事件

事件名 含义
readystatechange readyState 属性值发生变化触发该事件。
abort 请求终止时触发。
error 请求遇到错误时触发。注意,只有发生了网络层级别的异常才会触发此事件。
loadstart 接收到响应数据时触发。 xhr2
load 请求成功完成时触发。xhr2
loadend 当请求结束时触发, 无论请求成功 ( load) 还是失败 (aborerror)。xhr2
progress 当请求接收到更多数据时,周期性地触发。xhr2
timeout 在预设时间内没有接收到响应时触发。xhr2

2 跨域

2.1 同源策略

  • 同源策略是浏览器的一种安全策略。
  • 要求 ajax 代码所在的页面的 协议、域名、端口号与 ajax 请求的 URL 中 协议、域名、端口号保持一致
  • 解决同源策略,进行跨域: CORS JSONP

2.2 CORS 跨域资源共享

在服务端进行设置
添加一个响应头,设置允许的 域名

Access-Control-Allow-Origin: http://localhost:8080   
# 允许前面页面的域名是http://localhost:8080,才能跨域

Access-Control-Allow-Origin:*
# 允许所有的域名都可以跨域

2.3 JSONP

实现思路

****实现基础:
	***利用 script 标签也可以发送请求,天然支持跨域, script 会把响应到的内容作为 js 代码执行*******

实现步骤:(前端)
	1. 创建 script 标签
	2. 指定 script 标签的 src 属性值,src 的属性值就是请求地址, 把函数名通过url中的查询字符串传给后端
	3. 把 script 标签添加到 body 中
	4. 再把 script 标签从 body 中移除
	5. 定义获取数据的函数,该函数会被后端响应的内容调用,把数据传进来
	注意: 在 script 添加到 body 中的瞬间,发起请求,接收响应,调用了函数
	
	
实现步骤:(后端)
	1. 从 url 中的查询字符串里取出函数名
	2. 响应体内容是 js 代码,调用函数的js代码,把数据变为json格式作为函数的参数
	3. 做出响应

JSONP 缺点

只支持 GET 请求

JSONP案例-前端操作

<!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>jsonp</title>
</head>
<body>
    <h1>JSONP</h1>
    <hr>
    <button id="btn">请求数据</button>


    <script>
        
        /*
         后端给前端接口文档

         jsonp 请求
         地址: http://localhost:8080/getdata02?cb=函数名
        
        */

        // 点击按钮 发送请求
        var btn = document.querySelector('#btn');
        btn.onclick = function(){
            // 创建 script 标签
            var scriptEle = document.createElement('script');
            // 设置 script 标签的src 属性
            scriptEle.src = 'http://localhost:8080/getdata02?cb=getData';
            // 将 script 标签添加到文档结构, 添加到文档结构的那一刻,js代码就行了
            document.body.appendChild(scriptEle);
            // script 用完就销毁
            document.body.removeChild(scriptEle);
            
        };

        function getData(data) {
            console.log(data);
        }
    </script>

</body>
</html>

JSONP后端操作

// 导入模块
const path = require('path');
const express = require('express');

// 创建 express 实例
const app = express();

// 1. 同源策略 -----------------------------------------------------------------------
// 同源策略
app.get('/01-page', (req, res) => {
    res.sendFile(path.join(__dirname, '01-CORS.html'));
});
// 接收 ajax 请求
app.get('/getdata01', (req, res) => {
    // 设置响应头 允许跨域;  可以允许的前端页面的域名
    // res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
    
    // 允许所有的域名
    res.set('Access-Control-Allow-Origin', '*');

    res.send('hello ajax');
});
**// 2. jsonp -----------------------------------------------------------------------
// 打开 02-jsonp解决跨域.html 静态文件
app.get('/02-page', (req, res) => {
    res.sendFile(path.join(__dirname, 'jsonp请求.html'));
});**

// 接收到是 jsonp 的请求
app.get('/getdata02', (req, res) => {
    // // 定义数据
    const users = [
        {name:'李华0', age:90, address:'上海'},
        {name:'李华1', age:90, address:'上海'},
        {name:'李华2', age:90, address:'上海'},
        {name:'李华3', age:90, address:'上海'},
        {name:'李华4', age:90, address:'上海'}
    ];

    //从 url 中得到函数名
    let method = req.query.cb;
    // 定义响应体 js 代码
    let body = `${method}(${JSON.stringify(users)})`;
    //字符串内容会被当作js代码执行,前端拿到的是一个数组。

    res.send(body)


    
    // res.send(`getInfo(${JSON.stringify(users)})`)
  
});

// 开启服务
app.listen(8080, () => {
console.log(‘HTTP服务启动成功,端口号 8080’);
})


## 3. jQuery 中使用 Ajax

### 3.1 发起 ajax 请求的方法

```js
$.get(url, [data], callback, [dataType])
	url: 请求地址
    data: 发给服务端的数据  形式可以是字符串也可以是对象,自动把数据拼接到url上
    	  'a=100&b=200'
          {a:100,b:200}
    callback:成功接收到响应之后回调函数
    dataType: 指定响应内容的格式,回调获取内容自动处理
    
    
$.post(url, [data], callback, [dataType])
	url: 请求地址
    data: 发给服务端的数据  形式可以是字符串也可以是对象,自动把数据添加到请求体
    	  'a=100&b=200'
          {a:100,b:200}
    callback:成功接收到响应之后回调函数
    dataType: 指定响应内容的格式,回调获取内容自动处理
    
    
$.ajax()  发起任意方式的请求
	$.ajax({
        url: '/data',  // url
        type: 'POST',  // 请求方式
       // data: {a:100,b:200},  // 发送给服务端的数据(默认请求体类型是application/x-www-form-urlencoded)
        					    //如果post请求后台限定了为application/json,
        					   //当设置contentType为application/json还是出错时,把data也要转换一下
        contentType: 'application/json',//指定请求内容的类型	
        data:JSON.Stringify({a:100,b:200})				  												
        success: function(data){  // 响应成功之后的回调函数
            alert(data);
        },
        dataType: 'json'  // 指定响应内容的类型
    })

3.2 处理表单数据

$('input').serialize();  // 返回字符串 形式 'a=100&b=200', 直接作为 $.get $.post $.ajax 的参数

3.3 JSONP

$.getJSON('http://127.0.0.1:8080/product-data?cb=?', function(data) {
    console.log(data);
});

你可能感兴趣的:(大前端,ajax,前端,javascript)