> 文档中心 > 【Ajax原生+封装+扩展】入门到入土,这一篇就够了

【Ajax原生+封装+扩展】入门到入土,这一篇就够了

文章目录

    • 前言
      • 0.1 XML简介
      • 0.2 AJAX 特点
    • 1. HTTP相关
      • 1.1 HTTP请求交互基本过程
      • 1.2 HTTP请求报文
      • 1.3 HTTP响应报文
      • 1.4 post请求体参数格式
      • 1.5 不同类型的请求及作用
      • 1.6 一般http请求与Ajax请求的区别
      • 1.7 http状态码
    • 2. 原生AJAX基本使用(XHR)
      • 2.1 准备工作
      • 2.2 请求的基本操作
      • 2.3 如何设置请求头
      • 2.4 JSON数据请求
      • 2.5 nodemon
      • 2.6 请求超时和网络异常
      • 2.7 取消请求
      • 28 请求重复发送问题
      • 2.9 解决IE缓存问题
      • 2.8 Ajax函数封装
    • 3. 在jQuery中发送Ajax请求
      • 3.1 GET请求
      • 3.2 POST请求
      • 3.3 通用方法
    • 4. axios发送Ajax请求
      • axios函数发送请求
    • 5. 跨域
      • 5.1 同源策略
      • 5.2 解决方案1 ——JSONP
      • 5.3 解决方案2——CORS

前言

AJAX 全称为Asynchronous JavaScript And XML,也就是异步的JS和XML

  • 通过AJAX,可以在无刷新页面的情况下,向服务器发送异步请求,并获取来自服务端的数据,这也是AJAX最大的优势:无需刷新获取数据

AJAX的使用在网页中非常常见,比如上新闻网,往下刷着刷着,需要加载一会才能显示下面的信息,这就是触发到底事件,浏览器通过AJAX获取到新的数据,然后通过JS创建元素显现在网页中

异步的JS相信无需讲解,下面对XML简单进行说明

0.1 XML简介

XML 是可扩展标记语言,被设计用来传输和存储数据

XML和HTML在结构上类似,不同的是HTML里是预定义标签,如

而XML中没有预定义标签,均为自定义标签,用来表示(“形容”)数据

如下栗子:

<student>    <name>张三</name><age>18</age></student>//这就是一个承载某位学生的XML数据段

最早AJAX中传送和存储数据用的就是XML,不过,现在已经被JSON替代,

如下:

{"name":"张三","age":18}
  • JSON是一种纯数据格式,只包含属性
  • 简洁,在数据转换更加容易,灵活度远胜于 XML

0.2 AJAX 特点

  1. 优点

    • 无需刷新页面而与服务器进行通信
    • 允许根据用户事件来更新部分页面内容
  2. 缺点

    • 无浏览历史,无法回退

      没有页面刷新

    • 存在跨域问题

      无法从一个服务向另一个服务发送请求

    • SEO不友好

      AJAX获取的数据,爬虫爬不到(感兴趣可以去了解一下SEO),简单说明就是百度搜不到这些数据

1. HTTP相关

首先我们需要对HTTP有一定的了解

全名为超文本传输协议,其实就是一个互联网的规定,简单理解就是统一语言

想要全面的学习http,MAD文档是个不错的选择

点此可跳转

1.1 HTTP请求交互基本过程

【Ajax原生+封装+扩展】入门到入土,这一篇就够了

1.2 HTTP请求报文

包括四部分

  • 行包括三部分,请求类型(GET、POST等),URL路径,HTTP版本/1.1or1.0

  • 请求体类型

    Host: atguigu.comCookie: name=giuguContent-type: applicatiion/x-www-form-urlencodedUser-Agent: chrome 83//键值对格式
  • 空行

  • GET请求时,请求体为空,POST请求时,请求体可不为空

    username=admin&password=admin

1.3 HTTP响应报文

四部分

  • 包含三部分,协议版本——HTTP/1.1,响应状态码——如200表示OK(如常见的404),响应状态字符串

  • 格式跟请求报文头一样

  • 空行

  • 主要返回结果

    html文本、json文本、js、css、图片...

1.4 post请求体参数格式

  1. Content-Type:application/x-www-form-urlencoded;charset=utf-8

    用于键值对参数,参数的键值用=链接,参数之间用`&连接

  2. Content-Type: application/json;charset=utf-8

    用于json字符串参数

  3. Content-Type: multipart/form-data

    用于文件上传请求

1.5 不同类型的请求及作用

  1. GET:从服务端读取数据

  2. POST:向服务端添加新数据

  3. PUT:更新服务端数据

  4. DELETE:删除服务端数据

也就是查增改删

1.6 一般http请求与Ajax请求的区别

  • Ajax是特殊的http请求
  • 对于浏览器端,只有XHR,和fetch发出的才是Ajax请求,其他所有都是非Ajax请求
  • 浏览器响应:
    1. 接收一般http请求后,浏览器一般会直接显示响应体的数据,也就是刷新/跳转页面
    2. 接收Ajax请求后,浏览器并不会刷新,只是通过回调函数,传入响应体的数据

1.7 http状态码

无需考究太多,能知道代表什么就行,http状态码是在响应报文的行里面的。
200~300 表示OK,不过用得多的是200
404 表示服务端未接收到请求
500 服务器端错误,有时候就是服务器代码编译出错

这几个是比较常见的,后面发现没见过的一定要灵活应用搜索引擎

2. 原生AJAX基本使用(XHR)

xhr,全称为XMLHttpRequest,用于与服务器交互数据,是ajax功能实现所依赖的对象

2.1 准备工作

我们接下来通过案例实现Ajax的交互,从而学习Ajax

首先我们需要在服务端做一些准备

  1. 安装node.js

官方链接

打开命令行输入node -v若出现某个版本号,说明安装成功
  1. 安装express框架

利用命令行

npm init --yes初始化环境npm i express 下载express包,建议使用管理员身份打开VScode或命令行,否则可能出现err

2.2 请求的基本操作

如何建立浏览器与服务端联系,下面通过一个小例子说明

服务端:

//引入expressconst 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;      }}

当然,两个方法都是可用的


2.3 如何设置请求头

报文的其他部分我们都以及有了设置的方法,还差一个请求头

这个也是通过XHR对象的一个方法实现的

语法如下:

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

需要注意的是,当你使用post类型时,记得把服务端文件中的get改为post哦,否则无法接受到请求

2.4 JSON数据请求

接下来同样用一个例子让我们理解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属性

我们可以在浏览器端设置

  1. 第一种,手动设置

    let data = JSON.parse(xhr.response);result.innerHTML = data.name;
  2. 第二种,自动转化

    在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>JSON</title> <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>

2.5 nodemon

这里先来介绍一个工具

我们知道,当我们对服务端文件进行修改时,需要重新启动服务才能生效,这就有点繁琐了,而这个工具可以自动检测我们的文件是否修改,如果修改,它会帮我们自动重新启动服务

安装也是非常简单,在终端写下以下代码

npm install -g nodemon

等待安装,启动服务把node的代码换成用这一串代码,就代表使用这个工具拉

nodemon server.js

2.6 请求超时和网络异常

用户在浏览网页时时常会发生网络异常,或者网络速率低超时现象

这时我们可以提醒用户,“稍后重试” ——“友好信息,保证用户体验”

//这是设置超时的对象属性//此处设置为2秒xhr.timeout = 2000;//超时时间发生,调用回调函数xhr.ontimeout = function(){    alert('网络超时,请稍后重试')}//网络异常事件发生,调用回调函数xhr.onerror = function(){    alert('网络异常,请稍后重试');}

2.7 取消请求

有时用户可能因为某些原因,想要取消请求操作,如等的不耐烦,按错了

这时候,我们可以使用XHR对象的abort方法

xhr.abort();//注意,一般得设置个事件,把上面的代码放进去,比如按钮,当按下按钮,取消请求

28 请求重复发送问题

当用户快速触发事件多次发送请求,服务器压力变大,性能降低

解决方法:

重复发送请求时,将上一次未完成的请求取消

//创建一个判断是否正在发送请求的变量let isSending = false;//在事件内判断是否正在发送,如果是,取消请求然后再创建新请求//在判断之后将上述变量改为真(写在初始化前面)//这样用户发送第二次请求就会执行该if语句if(isSending)    xhr.abort();x = new XMLHttpRequset();isSending = true;...

2.9 解决IE缓存问题

在某些浏览器如IE,由于缓存机制的存在,Ajax只会发送第一次的请求,剩余多次请求不会再发送给浏览器而是直接加载缓存中的数据

解决方法:

浏览器的缓存是通过URL地址记录的,因此我们只需要修改URL,多次请求也可以发送啦

xhr.open('GET','/server?t='+Date.now());//给它加个时间戳,保证每次请求的URL都会不同

2.8 Ajax函数封装

重点来了,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);     } }    }

3. 在jQuery中发送Ajax请求

3.1 GET请求

$('button').btn(0).click(function(){    $.get('http://127.0.0.1:8000/server', {a:100, b:200}, function(data){  console.log(data);//这里获得从服务端传来的数据进行处理    } )})

3.2 POST请求

$('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

$其实也就是一个对象

3.3 通用方法

$.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('貌似出现了点问题')}})

4. axios发送Ajax请求

浅浅介绍一下,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函数发送请求

非常清晰,十分推荐

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'    }})

5. 跨域

5.1 同源策略

同源:协议、域名、端口号必须完全一样

注意,上述一个不同就是违背同源,也就是跨域

5.2 解决方案1 ——JSONP

非官方,是程序员自己想出来的

只支持GET请求

原理:

HTML中有些网页自带跨域能力,如imglinkscript

而JSONP就是利用script标签实现跨域请求的

具体使用:

  1. 动态创建script标签
  2. 设置src属性,设置回调函数
  3. 一般大家会把这里动态添加的script标签添加到body中
var script = document.creatElement('script');script.src = "http://localhost:52330/...";function callback(data){    ...};document.body.appendChild(script);

注意:

由于返回的字段相当于写在script标签里,所以应该为JS代码,才可以被解析

5.3 解决方案2——CORS

跨域资源共享,官方解决方案,不需要在客户端做任何特殊操作,完全在服务器中处理,支持get和post

  • 跨域资源共享标准新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源

原理:

通过设置响应头来告诉浏览器,该请求允许跨域,浏览器收到响应后就会给请求放行

具体使用:

重心就是服务端的设置:

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代码,才可以被解析