AJAX 全称为Asynchronous JavaScript And XML
,也就是异步的JS和XML
AJAX的使用在网页中非常常见,比如上新闻网,往下刷着刷着,需要加载一会才能显示下面的信息,这就是触发到底事件,浏览器通过AJAX获取到新的数据,然后通过JS创建元素显现在网页中
异步的JS相信无需讲解,下面对XML简单进行说明
XML 是可扩展标记语言,被设计用来传输和存储数据
XML和HTML在结构上类似,不同的是HTML里是预定义标签,如
而XML中没有预定义标签,均为自定义标签,用来表示(“形容”)数据
如下栗子:
<student>
<name>张三</name>
<age>18</age>
</student>
//这就是一个承载某位学生的XML数据段
最早AJAX中传送和存储数据用的就是XML,不过,现在已经被JSON
替代,
如下:
{"name":"张三","age":18}
JSON
是一种纯数据格式,只包含属性优点
缺点
无浏览历史,无法回退
没有页面刷新
存在跨域问题
无法从一个服务向另一个服务发送请求
SEO
不友好
AJAX获取的数据,爬虫爬不到(感兴趣可以去了解一下SEO
),简单说明就是百度搜不到这些数据
首先我们需要对HTTP有一定的了解
全名为超文本传输协议,其实就是一个互联网的规定,简单理解就是统一语言
想要全面的学习http,MAD文档是个不错的选择
点此可跳转
包括四部分
行
行包括三部分,请求类型(GET、POST等),URL路径,HTTP版本/1.1or1.0
头
请求体类型
Host: atguigu.com
Cookie: name=giugu
Content-type: applicatiion/x-www-form-urlencoded
User-Agent: chrome 83
//键值对格式
空行
体
GET请求时,请求体为空,POST请求时,请求体可不为空
username=admin&password=admin
四部分
行
包含三部分,协议版本——HTTP/1.1,响应状态码——如200表示OK(如常见的404),响应状态字符串
头
格式跟请求报文头一样
空行
体
主要返回结果
html文本、json文本、js、css、图片...
Content-Type:application/x-www-form-urlencoded;charset=utf-8
用于键值对参数,参数的键值用=
链接,参数之间用`&连接
Content-Type: application/json;charset=utf-8
用于json
字符串参数
Content-Type: multipart/form-data
用于文件上传请求
GET
:从服务端读取数据
POST
:向服务端添加新数据
PUT
:更新服务端数据
DELETE
:删除服务端数据
也就是查增改删
XHR
,和fetch
发出的才是Ajax请求,其他所有都是非Ajax请求无需考究太多,能知道代表什么就行,http状态码是在响应报文的行里面的。
200~300
表示OK,不过用得多的是200
404
表示服务端未接收到请求
500
服务器端错误,有时候就是服务器代码编译出错
这几个是比较常见的,后面发现没见过的一定要灵活应用搜索引擎
xhr,全称为XMLHttpRequest
,用于与服务器交互数据,是ajax功能实现所依赖的对象
我们接下来通过案例实现Ajax的交互,从而学习Ajax
首先我们需要在服务端做一些准备
官方链接
打开命令行输入
node -v
若出现某个版本号,说明安装成功
利用命令行
npm init --yes
初始化环境
npm i express
下载express包,建议使用管理员身份打开VScode或命令行,否则可能出现err
如何建立浏览器与服务端联系,下面通过一个小例子说明
服务端:
//引入express
const express = require('express')
//创建应用对象
const obj = express();
//创建路由规则
//request 对请求报文的封装
//response 对响应报文的封装
obj.get('/server', (request, response)=>{
response.setHeader('Access-Control-Allow-Origin', '*');
response.send('HELLO AJAX');
})
//监听端口启动服务
obj.listen(8000, ()=>{
console.log('服务已经启动,8000端口监听中...');
})
html:
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 GET 请求title>
<style>
#result{
width: 200px;
height: 200px;
border: 5px solid #90b;
}
style>
head>
<body>
<button>点击此发送请求button>
<div id="result">div>
<script>
const btn = document.getElementsByTagName('button')[0];
const result = document.getElementById('result');
//注册事件
btn.onclick = function(){
//四步建立关系
//1,创建对象
const xhr = new XMLHttpRequest();
//2,初始化,设置请求方法和URL
xhr.open('GET', 'http://127.0.0.1:8000/server');
//3,发送
xhr.send();
//4,事件绑定,处理返回的结果
xhr.onreadystatechange = function(){
//判断是否返回了所有结果
if(xhr.readyState === 4){
//判断是否成功,通过状态码
if(xhr.status >= 200 && xhr.status <=300){
//设置result的文本
result.innerHTML = xhr.response;
}
}
}
}
script>
body>
html>
在VScode里打开终端,执行服务端js文件
node .\server.js
此时设置的监听器打开
再把html在浏览器中打开,便可实现交互效果,你可以点点那个按钮看看哦
上述的GET请求的案例,作用就是在服务端获取信息,大家还可以试试类型完成交互,本文主讲GET 和POST两种类型
补充:
GET请求设置参数
大家有时可以看到某些URL后面会带着一长串东西,那就是浏览器向服务端传输的数据参数
格式如下:
在域名后加上?
作为分割,紧接着用参数=值
&参数=值
的循序叠加
栗子如下:
http://127.0.0.1:8000/server?a=100&b=200&c=300
//在代码里则表现为
xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
上述请求的基本操作对于GET和POST均成立
这里提的是他们设置参数方式的不同
对于POST设置参数则为:
xhr.send('a=100&b=200&c=300');
事件绑定:
也就是第四个步骤,目前较新的用法是onload事件
xhr.onload = function(){
if(xhr.status >= 200 && xhr.status <=300){
//设置result的文本
result.innerHTML = xhr.response;
}
}
当然,两个方法都是可用的
报文的其他部分我们都以及有了设置的方法,还差一个请求头
这个也是通过XHR对象的一个方法实现的
语法如下:
xhr.setRequestHeader('Content-Type', 'application/x-www-from-urlencoded');
需要注意的是,当你使用post类型时,记得把服务端文件中的get改为post哦,否则无法接受到请求
接下来同样用一个例子让我们理解JSON
首先先有几个知识点
我们知道,JSON就是存储数据的,没有标签,没有函数
那么如果我们想要获取到服务端的数据
const data = {
name : 'zhangsan';
}
那么从前面学的知识,我们可以想到,在JS文件中,对
response.send('...');
进行修改即可,需要注意的是,该send方法只能传递字符串
那我们还可以利用一个对象的方法
let str = JSON.stringify(data);
对该data对象进行字符串转换,那么合起来代码就是:
const data = {
name : 'zhangsan'
};
let str = JSON.stringify(data);
response.send(str);
那么在浏览器端,就会接收到这样一段数据
name : 'zhangsan'
如果我想得到值,去掉这个name怎么办?
在日常的应用中,大多数情况也是不需要这个name属性
我们可以在浏览器端设置
第一种,手动设置
let data = JSON.parse(xhr.response);
result.innerHTML = data.name;
第二种,自动转化
在XHR对象中,有一个设置返回数据类型的格式
我们可以这样设置它,
xhr.responseType = 'json';
这句代码只需要在前面定义,后面只要我们需要用到某个值,都可以直接
result.innerHTML = xhr.response.name;
灰常方便!!
服务端:
const express = require('express')
const app = express();
app.all('/server', (request, response) => {
// 设置响应头, 设置允许跨域
response.setHeader('Access-Control-Allow-Origin', '*');
// 响应一个数据
const data = {
name: 'zhangsan'
};
// 对 对象 进行 字符串 转换
let str = JSON.stringify(data)
// 设置响应体
response.send(str);
});
html:
DOCTYPE html>
<html lang='en'>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewpport" content="width=device-width, initial-scale=1.0">
<title>JSONtitle>
<style>
#result{
width: 200px;
height: 200ox;
border: 5px solid #90b;
}
style>
head>
<body>
<div id="result">div>
<script>
const result = document.getElementById('result');
//绑定键盘按下事件
window.onkeydown = function(){
//发送请求
const xhr = new XMLHttpRequest();
//响应体数据自动转换为JSON
xhr.responseType = "json";
//初始化
xhr.open('GET', 'http://127.0.0.1:8000/server');
//发送
xhr.send();
//事件绑定
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 & xhr.status <= 300){
//手动数据转化
//let data = JSON.parse(xhr.response);
//result.innerHTML = data.name;
//自动
result.innerHTML = xhr.response.name;
}
}
}
}
script>
body>
html>
这里先来介绍一个工具
我们知道,当我们对服务端文件进行修改时,需要重新启动服务才能生效,这就有点繁琐了,而这个工具可以自动检测我们的文件是否修改,如果修改,它会帮我们自动重新启动服务
安装也是非常简单,在终端写下以下代码
npm install -g nodemon
等待安装,启动服务把node的代码换成用这一串代码,就代表使用这个工具拉
nodemon server.js
用户在浏览网页时时常会发生网络异常,或者网络速率低超时现象
这时我们可以提醒用户,“稍后重试” ——“友好信息,保证用户体验”
//这是设置超时的对象属性
//此处设置为2秒
xhr.timeout = 2000;
//超时时间发生,调用回调函数
xhr.ontimeout = function(){
alert('网络超时,请稍后重试')
}
//网络异常事件发生,调用回调函数
xhr.onerror = function(){
alert('网络异常,请稍后重试');
}
有时用户可能因为某些原因,想要取消请求操作,如等的不耐烦,按错了
这时候,我们可以使用XHR对象的abort方法
xhr.abort();
//注意,一般得设置个事件,把上面的代码放进去,比如按钮,当按下按钮,取消请求
当用户快速触发事件多次发送请求,服务器压力变大,性能降低
解决方法:
重复发送请求时,将上一次未完成的请求取消
//创建一个判断是否正在发送请求的变量
let isSending = false;
//在事件内判断是否正在发送,如果是,取消请求然后再创建新请求
//在判断之后将上述变量改为真(写在初始化前面)
//这样用户发送第二次请求就会执行该if语句
if(isSending)
xhr.abort();
x = new XMLHttpRequset();
isSending = true;
...
在某些浏览器如IE,由于缓存机制的存在,Ajax只会发送第一次的请求,剩余多次请求不会再发送给浏览器而是直接加载缓存中的数据
解决方法:
浏览器的缓存是通过URL地址记录的,因此我们只需要修改URL,多次请求也可以发送啦
xhr.open('GET','/server?t='+Date.now());
//给它加个时间戳,保证每次请求的URL都会不同
重点来了,Ajax请求发送步骤不少,一次两次还行,但是实际开发中我们会经常用到Ajax请求,这时候如果还一个一个写就多出了很多重复代码,因此我们一般会用一个函数封装Ajax的基本操作
function ajax (options){
//设置默认值
var defaults = {
type: 'get',
url: '',
data: {},
header: {
'Content-Type': 'appliction/x-www-form-urlencoded'
},
success: function(){},
error: function(){
alert('请求错误');
}
}
//用option覆盖defaults对象,传递的参数没有设置就用默认值
Object.assign(defaults, options);
var xhr = new XMLHttpRequest();
//获取请求参数字符串
var params = '';
for(var attr in defaults.data){
params += attr + '=' + defaults.data['attr'] + '&';
}
params = params.substring(0, [params.length - 1]);
//判断请求方式并发送请求体
if(defaults.type == 'get'){
defaults.url = defaults.url + '?' + params;
}
xhr.open(defaults.type, defaults.url);
if(defaults.type == 'post'){
xhr.send(params);
}else{
xhr.send();
}
//获取返回的数据
xhr.onload = function(){
var contentType = xhr.getResponseHeader('Content-Type');
var responseText = xhr.responseText;
if(contentType.includes('application/json')){
responseText = JSON.parse(responseText);
}
if(xhr.status == 200){
defaults.success(responseText, xhr);
}else{
defaults.error(responseText, xhr);
}
}
}
$('button').btn(0).click(function(){
$.get('http://127.0.0.1:8000/server', {a:100, b:200}, function(data){
console.log(data);//这里获得从服务端传来的数据进行处理
} )
})
$('button').btn(0).click(function(){
$.post('http://127.0.0.1:8000/server', {a:100, b:200}, function(data){
console.log(data);//这里获得从服务端传来的数据进行处理
} )
})
上面两个的格式就是
$.get/post(url, [data], [callback], [type])
type可选,类似原生的xhr.responseType
$其实也就是一个对象
$.ajax({
url: 'http://127.0.0.1:8000/server',
data: {a:100, b:200},
type: 'GET',
dataType: 'json',
//回调函数
success: function(data){
console.log(data);
},
//还可以设置超时时间,时间到取消请求
timeout: 2000,
//失败回调
error: function(){
console.log('貌似出现了点问题');
}
});
浅浅介绍一下,axios是目前非常流行的Ajax封装库,可以很方便地实现Ajax请求的发送
到bootcdn搜索把axios的scrip标签格式复制拿过来就行了
现在发送请求(GET)
//GET请求
axios.get('http://127.0.0.1:8000/server', {
//url参数
params: {
id:100,
vip:7
},
//请求头信息
headers:{
name: 'zhangsan',
age: 18
}
}).then(value => {
console.log(value);
})//相当于回调函数
axios里还有一个baseURL
当你在前面配置了
axios.defaults.baseURL = "http://127.0.0.1:8000";
后面URL设置就可以省略这前面的一部分
axios.get('/server', ...)
(POST)
请求体设置
axios.post('/server', {
username: 'admin',
password: 'admin'
}, {
params:{
id:200,
vip:7
}
headers: {
height: 180,
weight:150
}
})
axios一般设置三个参数
非常清晰,十分推荐
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/server', //这里还可以用baseURL简化一下的
parans: {
level: 30,
vip:5
},
headers: {
a: 100;
b:200
},
//这里是请求体参数
data:{
username: 'admin',
password: 'admin'
}
})
同源:协议、域名、端口号必须完全一样
注意,上述一个不同就是违背同源,也就是跨域
非官方,是程序员自己想出来的
只支持GET请求
原理:
HTML中有些网页自带跨域能力,如img
、link
、script
而JSONP就是利用script标签实现跨域请求的
具体使用:
script
标签var script = document.creatElement('script');
script.src = "http://localhost:52330/...";
function callback(data){
...
};
document.body.appendChild(script);
注意:
由于返回的字段相当于写在script标签里,所以应该为JS代码,才可以被解析
跨域资源共享,官方解决方案,不需要在客户端做任何特殊操作,完全在服务器中处理,支持get和post
原理:
通过设置响应头来告诉浏览器,该请求允许跨域,浏览器收到响应后就会给请求放行
具体使用:
重心就是服务端的设置:
router.get('/ajaxtest', function(require, response)=>{
//设置响应头
response.setHeader('Access-Control-Allow-Origin', '*'); //星号表示统配,都可以跨域
//如果只想能跨域某个网页
//response.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8000');
})
函数
3. 一般大家会把这里动态添加的script标签添加到body中
var script = document.creatElement('script');
script.src = "http://localhost:52330/...";
function callback(data){
...
};
document.body.appendChild(script);
注意:
由于返回的字段相当于写在script标签里,所以应该为JS代码,才可以被解析