0
点赞
收藏
分享

微信扫一扫

(八)Ajax

老榆 2022-04-15 阅读 15

文章目录

一、Ajax 基础

1. 认识 Ajax

(1) Ajax 是什么
  • Ajax 是 Asynchronous JavaScript and XML(异步 JavaScript 和 XML)的简写
  • Ajax 中的异步:可以异步地向服务器发送请求,在等待响应的过程中,不会阻塞当前页面,浏览器可以做自己的事情。直到成功获取响应后,浏览器才开始处理响应数据
  • XML(可扩展标记语言)是前后端数据通信时传输数据的一种格式
    XML 现在已经不怎么用了,现在比较常用的是 JSON
  • Ajax 其实就是浏览器与服务器之间的一种异步通信方式
  • 使用 Ajax 可以在不重新加载整个页面的情况下,对页面的某部分进行更新
(2) 搭建 Ajax 开发环境
  • Ajax 需要服务器环境,非服务器环境下,很多浏览器无法正常使用 Ajax
    • VSCode:Live Server
    • Windows:phpStudy
    • Mac:MAMP

2. Ajax 的基本用法

(1) XMLHttpRequest
  • Ajax 想要实现浏览器与服务器之间的异步通信,需要依靠 XMLHttpRequest,它是一个构造函数
  • 不论是 XMLHttpRequest,还是 Ajax,都没有和具体的某种数据格式绑定
(2) Ajax 的使用步骤

1)创建 xhr 对象:

const xhr = new XMLHttpRequest();

2)监听事件,处理响应:
当获取到响应后,会触发 xhr 对象的 readystatechange 事件,可以在该事件中对响应进行处理

xhr.onreadystatechange = () => {
	if (xhr.readyState !== 4) return;

	// HTTP CODE
	// 获取到响应后,响应的内容会自动填充 xhr 对象的属性
	// xhr.status:HTTP  200、404
	// xhr.statusText:HTTP 状态说明 OK、Not Found
	if ((xhr.status >= 200) & (xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};
  • readystatechange 事件也可以配合 addEventListener 使用,不过要注意,IE6~8 不支持
    addEventListener
    xhr.addEventListener('readystatechange', () => {}, fasle);
  • 为了兼容性,readystatechange 中不使用 this,而是直接使用 xhr
  • 由于兼容性的原因,最好放在 open 之前
  • readystatechange 事件监听 readyState 这个状态的变化,它的值从 0 ~ 4,一共 5 个状态:
    0:未初始化。尚未调用 open()
    1:启动。已经调用 open(),但尚未调用 send()
    2:发送。已经调用 send(),但尚未接收到响应
    3:接收。已经接收到部分响应数据
    4:完成。已经接收到全部响应数据,而且已经可以在浏览器中使用了

3)准备发送请求:
调用 open 并不会真正发送请求,而只是做好发送请求前的准备工作

xhr.open(
	'HTTP 方法 GET、POST、PUT、DELETE',
	'地址 URL https://www.imooc.com/api/http/search/suggest?words=js ./index.html ./index.xml ./index.txt',
	true
);

4)发送请求:
调用 send() 正式发送请求
send() 的参数是通过请求体携带的数据

xhr.send(null);
(3) 使用 Ajax 完成前后端通信
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState !== 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
		console.log(typeof xhr.responseText);
	}
};
xhr.open('GET', url, true);
xhr.send(null);

3. GET 请求

(1) 携带数据
  • GET 请求不能通过请求体携带数据,但可以通过请求头携带
const url =
	'https://www.imooc.com/api/http/search/suggest?words=js&username=mike&age=18';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('GET', url, true);
xhr.send(null);

// 不会报错,但不会发送数据
xhr.send('sex=male');
(2) 数据编码
  • 如果携带的数据是非英文字母的话,比如说汉字,就需要编码之后再发送给后端,不然会造成乱码问题
  • 可以使用 encodeURIComponent() 编码
const url = `https://www.imooc.com/api/http/search/suggest?words=${encodeURIComponent(
        '前端'
      )}`;
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('GET', url, true);
xhr.send(null);

4. POST 请求

(1) 携带数据
  • POST 请求主要通过请求体携带数据,同时也可以通过请求头携带
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('POST', url, true);

// 如果想发送数据,直接写在 send() 的参数位置,一般是字符串
xhr.send('username=mike&age=18');

// 不能直接传递对象,需要先将对象转换成字符串的形式
xhr.send({
	username: 'mike',
	age: 18
});
// [object Object]
(2) 数据编码
  • 可以使用 encodeURIComponent() 编码
xhr.send(`username=${encodeURIComponent('张三')}&age=18`);

二、JSON

1. 认识 JSON

(1) JSON 是什么
  • JSON 全称是 JavaScript Object Notation
  • JSON:Ajax 发送和接收数据的一种格式
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('GET', url, true);
xhr.send(null);

// {"code":200,"data":[{"word":"jsp"},{"word":"js"},{"word":"json"},{"word":"js \u5165\u95e8"},{"word":"jstl"}]}
// HTML/XML
(2) 为什么需要 JSON
  • JSON 有 3 种形式,每种形式的写法都和 JS 中的数据类型很像,可以很轻松的和 JS 中的数据类型互相转换
  • JS -> JSON -> PHP / Java
  • PHP / Java -> JSON -> JS

2. JSON 的 3 种形式

(1) 简单值形式
  • JSON 的简单值形式就对应着 JS 中的基础数据类型:数字、字符串、布尔值、null
  • 注意事项:
    ① JSON 中没有 undefined 值
    ② JSON 中的字符串必须使用双引号
    ③ JSON 中是不能注释的
(2) 对象形式
  • JSON 的对象形式就对应着 JS 中的对象
  • 注意事项:
    ① JSON 中对象的属性名必须用双引号,属性值如果是字符串也必须用双引号
    ② JSON 中只要涉及到字符串,就必须使用双引号
    ③ 不支持 undefined
(3) 数组形式
  • JSON 的数组形式就对应着 JS 中的数组 [1, "hi", null]
  • 注意事项:
    ① 数组中的字符串必须用双引号
    ② JSON 中只要涉及到字符串,就必须使用双引号
    ③ 不支持 undefined
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
		console.log(typeof xhr.responseText);
	}
};

// xhr.open('GET', './plain.json', true);
// xhr.open('GET', './obj.json', true);
xhr.open('GET', './arr.json', true);

xhr.send(null);

3. JSON 的常用方法

(1) JSON.parse()
  • JSON.parse() 可以将 JSON 格式的字符串解析成 JS 中的对应值
  • 一定要是合法的 JSON 字符串,否则会报错
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
		console.log(typeof xhr.responseText);

		console.log(JSON.parse(xhr.responseText));
		console.log(JSON.parse(xhr.responseText).data);
	}
};

// xhr.open('GET', './plain.json', true);
// xhr.open('GET', './obj.json', true);
// xhr.open('GET', './arr.json', true);

xhr.open(
'GET',
'https://www.imooc.com/api/http/search/suggest?words=js',
true
);

xhr.send(null);
(2) JSON.stringify()
  • JSON.stringify() 可以将 JS 的基本数据类型、对象或者数组转换成 JSON 格式的字符串
console.log(
	JSON.stringify({
		username: 'mike',
		age: 18
	})
);

const xhr = new XMLHttpRequest();

xhr.open(
	'POST',
	'https://www.imooc.com/api/http/search/suggest?words=js',
	true
);

xhr.send(
	JSON.stringify({
		username: 'mike',
		age: 18
	})
);
(3) 使用 JSON.parse() 和 JSON.stringify() 封装 localStorage
import { get, set, remove, clear } from './storage.js';

set('username', 'mike');
console.log(get('username'));

set('zs', {
	name: '张三',
	age: 18
});

console.log(get('zs'));

remove('username');
clear();

三、跨域

1. 跨域是什么

  • 同域,不是跨域
const url = './index.html';
// const url = 'http://127.0.0.1:5500/.../index.html';

http://127.0.0.1:5500

  • 不同域,跨域,被浏览器阻止
const url = 'https://www.imooc.com';
const xhr = new XMLHttpRequest();

// Access to XMLHttpRequest at 'https://www.imooc.com/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
  • 向一个域发送请求,如果要请求的域和当前域是不同域,就叫跨域
  • 不同域之间的请求,就是跨域请求
xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('GET', url, true);

xhr.send(null);

2. 什么是不同域,什么是同域

  • https(协议): //www.imooc.com(域名):443(端口号)/course/list(路径)
  • 协议、域名、端口号,任何一个不一样,就是不同域
  • 与路径无关,路径一不一样无所谓
  • 不同域:
    https://www.imooc.com:443/course/list
    http://www.imooc.com:80/course/list
  • 不同域:
    http://www.imooc.com:80/course/list
    http://m.imooc.com:80/course/list
    http://imooc.com:80/course/list
  • 同域:
    http://imooc.com:80
    http://imooc.com:80/course/list

3. 跨域请求为什么会被阻止

  • 阻止跨域请求,其实是浏览器本身的一种安全策略–同源策略
  • 其他客户端或者服务器都不存在跨域被阻止的问题

4. 跨域解决方案

  • ① CORS 跨域资源共享
  • ② JSONP
  • 优先使用 CORS 跨域资源共享,如果浏览器不支持 CORS 的话,再使用 JSONP
(1) CORS 跨域资源共享
// const url = 'https://www.imooc.com';
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.responseText);
	}
};

xhr.open('GET', url, true);
xhr.send(null);
  • Access-Control-Allow-Origin: *
    表明允许所有的域名来跨域请求它,*是通配符,没有任何限制
  • 只允许指定域名的跨域请求:
    Access-Control-Allow-Origin: http://127.0.0.1:5500
  • 使用 CORS 跨域的过程:
    ① 浏览器发送请求
    ② 后端在响应头中添加 Access-Control-Allow-Origin 头信息
    ③ 浏览器接收到响应
    ④ 如果是同域下的请求,浏览器不会额外做什么,这次前后端通信就圆满完成了
    ⑤ 如果是跨域请求,浏览器会从响应头中查找是否允许跨域访问
    ⑥ 如果允许跨域,通信圆满完成
    ⑦ 如果没找到或不包含想要跨域的域名,就丢弃响应结果
  • CORS 的兼容性:
    IE10 及以上版本的浏览器可以正常使用 CORS
(2) JSONP
  • JSONP 的原理:
    script 标签跨域不会被浏览器阻止
    JSONP 主要就是利用 script 标签,加载跨域文件
  • 使用 JSONP 实现跨域:
// 服务器端准备好 JSONP 接口
// https://www.imooc.com/api/http/jsonp?callback=handleResponse

// 手动加载 JSONP 接口或动态加载 JSONP 接口
const script = document.createElement('script');
script.src =
	'https://www.imooc.com/api/http/jsonp?callback=handleResponse';
document.body.appendChild(script);

// 声明函数
const handleResponse = data => {
	console.log(data);
};

// handleResponse({
//   code: 200,
//   data: [
//     {
//       word: 'jsp'
//     },
//     {
//       word: 'js'
//     },
//     {
//       word: 'json'
//     },
//     {
//       word: 'js 入门'
//     },
//     {
//       word: 'jstl'
//     }
//   ]
// });

四、XHR 对象

1. XHR 的属性

(1) responseType 和 response 属性
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		// 文本形式的响应内容
		// responseText 只能在没有设置 responseType 或者 responseType = '' 或 'text' 的时候才能使用
		console.log('responseText:', xhr.responseText);

		// 可以用来替代 responseText
		console.log('response:', xhr.response);
		// console.log(JSON.parse(xhr.responseText));
	}
};
xhr.open('GET', url, true);

xhr.responseType = '';
xhr.responseType = 'text';

xhr.responseType = 'json';

xhr.send(null);

IE6~9 不支持,IE10 开始支持

(2) timeout 属性
  • 设置请求的超时时间(单位 ms)
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.response);
	}
};
xhr.open('GET', url, true);

xhr.timeout = 10000;

xhr.send(null);

IE6~7 不支持,IE8 开始支持

(3) withCredentials 属性
  • 指定使用 Ajax 发送请求时是否携带 Cookie
  • 使用 Ajax 发送请求,默认情况下,同域时,会携带 Cookie;跨域时,不会携带 Cookie
  • xhr.withCredentials = true; 最终能否成功跨域携带 Cookie,还要看服务器同不同意
// 同域
// const url = './index.html';
// 跨域
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.response);
	}
};
xhr.open('GET', url, true);

xhr.withCredentials = true;

xhr.send(null);

IE6~9 不支持,IE10 开始支持

2. XHR 的方法

(1) abort()
  • 用来终止当前请求
  • 一般配合 abort 事件一起使用
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.response);
	}
};
xhr.open('GET', url, true);

xhr.send(null);

// 发送完请求后调用
xhr.abort();
(2) setRequestHeader()
  • 可以设置请求头信息
    xhr.setRequestHeader(头部字段的名称, 头部字段的值);
// const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const url = 'https://www.imooc.com/api/http/json/search/suggest?words=js';

const xhr = new XMLHttpRequest();

xhr.onreadystatechange = () => {
	if (xhr.readyState != 4) return;

	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
		console.log(xhr.response);
	}
};
xhr.open('POST', url, true);

// 请求头中的 Content-Type 字段用来告诉服务器,浏览器发送的数据是什么格式的
// xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// xhr.send('username=mike&age=18');

xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(
	JSON.stringify({
		username: 'mike'
	})
);

// xhr.send(null);

3. XHR 的事件

(1) load 事件
  • 响应数据可用时触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

// xhr.onload = () => {
// 	if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
//     console.log(xhr.response);
//   }
// };

// 与 addEventListener 搭配使用
xhr.addEventListener(
	'load',
	() => {
		if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
			console.log(xhr.response);
		}
	},
	false
);

xhr.open('GET', url, true);

xhr.send(null);

IE6~8 不支持 load 事件

(2) error 事件
  • 请求发生错误时触发
// const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const url = 'https://www.iimooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.addEventListener(
	'load',
	() => {
		if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
			console.log(xhr.response);
		}
	},
	false
);

xhr.addEventListener(
	'error',
	() => {
		console.log('error');
	},
	false
);

xhr.open('GET', url, true);

xhr.send(null);

IE10 开始支持

(3) abort 事件
  • 调用 abort() 终止请求时触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.addEventListener(
	'load',
	() => {
		if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
			console.log(xhr.response);
		}
	},
	false
);

xhr.addEventListener(
	'abort',
	() => {
		console.log('abort');
	},
	false
);

xhr.open('GET', url, true);

xhr.send(null);

xhr.abort();

IE10 开始支持

(4) timeout 事件
  • 请求超时后触发
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = new XMLHttpRequest();

xhr.addEventListener(
	'load',
	() => {
		if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
			console.log(xhr.response);
		}
	},
	false
);

xhr.addEventListener(
	'timeout',
	() => {
		console.log('timeout');
	},
	false
);

xhr.open('GET', url, true);

xhr.timeout = 10;

xhr.send(null);

IE8 开始支持

五、Ajax 进阶

1. FormData

<body>
    <form
      id="login"
      action="https://www.imooc.com/api/http/search/suggest?words=js"
      method="POST"
      enctype="multipart/form-data"
    >
      <input type="text" name="username" placeholder="用户名" />
      <input type="password" name="password" placeholder="密码" />
      <input id="submit" type="submit" value="登录" />
    </form>

    <script>
      // 1.使用 Ajax 提交表单

      // 2.FormData 的基本用法
      // 通过 HTML 表单元素创建 FormData 对象
      // const fd = new FormData(表单元素);
      // xhr.send(fd);

      // 通过 append() 方法添加数据
      // const fd = new FormData(表单元素);
      // fd.append('age', 18);
      // fd.append('sex', 'male');
      // xhr.send(fd);

      // IE10 及以上可以支持

      const login = document.getElementById('login');
      // console.log(login.username);
      // console.log(login.password);
      const { username, password } = login;
      const btn = document.getElementById('submit');
      const url = 'https://www.imooc.com/api/http/search/suggest?words=js';

      btn.addEventListener(
        'click',
        e => {
          // 阻止表单自动提交
          e.preventDefault();

          // 表单数据验证

          // 发送 Ajax 请求
          const xhr = new XMLHttpRequest();

          xhr.addEventListener(
            'load',
            () => {
              if (
                (xhr.status >= 200 && xhr.status < 300) ||
                xhr.status === 304
              ) {
                console.log(xhr.response);
              }
            },
            false
          );

          xhr.open('POST', url, true);

          // 组装数据
          // const data = `username=${username.value}&password=${password.value}`;

          // FormData 可用于发送表单数据
          const data = new FormData(login);
          // data.append('age', 18);
          // data.append('sex', 'male');
          // console.log(data);
          // for (const item of data) {
          //   console.log(item);
          // }

          // xhr.setRequestHeader(
          //   'Content-Type',
          //   'application/x-www-form-urlencoded'
          // );

          xhr.send(data);

          // xhr.send('username=alex&password=12345');
        },
        false
      );
    </script>
  </body>

2. 封装 Ajax

3. 使用 Promise 改造封装好的 Ajax

六、

举报

相关推荐

0 条评论