AJAX笔记

发布时间 2023-07-14 16:17:03作者: 平平无奇的程序媛

第一章:原生 AJAX

1.1 AJAX 简介

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

通过 AJAX 可以在浏览器中向服务器发送异步请求,最大的优势:无刷新获取数据。

AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。

1.2 XML 简介

XML 可扩展标记语言。

XML 被设计用来传输和存储数据。

XML 和 HTML 类似,不同的是 HTML 中都是预定义标签,而 XML 中没有预定义标签,

全都是自定义标签,用来表示一些数据。

比如说我有一个学生数据:

name = "孙悟空" ; age = 18 ; gender = "男" ;

用 XML 表示:

<student>

	<name>孙悟空</name>

	<age>18</age>

	<gender>男</gender>

</student>

现在已经被 JSON 取代了。

用 JSON 表示:

{"name":"孙悟空","age":18,"gender":"男"}

1.3 AJAX 的特点

优点

  • 可以无需刷新页面而与服务器端进行通信。

  • 允许你根据用户事件来更新部分页面内容。

缺点

  • 没有浏览历史,不能回退

  • 存在跨域问题(同源)

  • SEO 不友好爬虫获取不到数据)

1.4 HTTP协议

超文本传输协议,详细规定了浏览器和万维网服务器之间互相通信的规则

请求报文

注意:GET请求报文请求体为空

URL里的参数解析

响应报文

请求体

1.5 Express框架

安装包:npm init - -yes

安装express框架:npm i express

使用express框架

​ 设置允许跨域: 在步骤3添加

response.setHeader('Access-Control-Allow-Origin','*');

​ 响应一个页面:sendFile需要写绝对路径

response.sendFile(__dirname+'/index.html');

response.end()与response.send()区别在于 response.end()不会加特殊的响应头

第二章:AJAX的使用

2.1 核心对象

XMLHttpRequest,AJAX 的所有操作都是通过该对象进行的。

2.2 使用步骤

先在script标签里先获取dom元素(button等)然后给元素绑定事件并在事件函数里:

  • 1、创建XMLHttpRequest对象

    const xhr = new XMLHttpRequest ();

  • 2、设置请求信息:请求方法和 url [可选:设置url参数]

    xhr.open( method, url );

    xhr.open('GET','http://127.0.0.1:8080/server?a=100&b=200&c=300');

​ //还可以设置请求头,一般不设置

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

  • 3、发送请求 xhr.send();

    xhr.send(body)

​ 注意:get 请求不传 body 参数,只有 post 请求使用`

  • 4、接收响应:事件绑定 处理服务端返回的结果

    • xhr.responseXML 接收 xml 格式的响应数据

    • xhr.responseText 接收文本格式的响应数据。如:const text = xhr.responseText;

    • xhr.status //状态码

    • xhr.status Text //状态字符串

    • xhr.getAllResponseHeaders() //所有响应头

    • xhr.response //响应体

      xhr.onreadystatechange = function (){
      //4.1判断(4表示:服务端返回了所有的结果)
      if(xhr.readyState === 4){
      //4.2 判断响应状态码 2xx 即为成功
      if(xhr.status >= 200 && xhr.status <300){
      //4.3 处理结果 行 头 空行 体
      result.innerHTML = xhr.response
      }
      }

响应状态码
  • 1xx(临时响应)
    表示临时响应并需要请求者继续执行操作的状态代码。

  • 2xx (成功)
    表示成功处理了请求的状态代码。

  • 3xx (重定向)
    表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。

  • 4xx(请求错误)
    这些状态代码表示请求可能出错,妨碍了服务器的处理。

  • 5xx(服务器错误)
    这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

常见状态码:

  • 200 - 服务器成功返回网页

  • 403 (禁止) 服务器拒绝请求

  • 404 - 请求的网页不存在

  • 500 (服务器内部错误) 服务器遇到错误,无法完成请求。

  • 503 - 服务不可用

  • 505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

post请求设置请求体(参数)

post请求设置请求头(预定义、自定义)

2.3 服务端响应JSON数据

后台对响应体data 对象 ( 如{name: 'wdt', age: 20} ) 进行字符串转换

let str = JSON.stringify(data);

在前台手动将字符串转换为对象

let data = JSON.parse (xhr.response );

在前台自动将获取的服务端字符串转换成对象:

//设置响应体数据的类型

xhr.responseType = 'json';

2.4 nodemon自动重启工具

安装:npm install -g nodemon

启动服务: nodemon server.js

2.5 IE缓存问题

问题:在一些浏览器中(IE),由于缓存机制的存在,ajax 只会发送的第一次请求,剩

余多次请求不会在发送给浏览器而是直接加载本地缓存中的数据。数据不是服务器返回的最新数据

解决方式:浏览器的缓存是根据 url 地址来记录的,所以我们只需要修改 url 地址,在URL后面加参数,例如时间戳,即可避免缓存问题。实际工作中不需要自己加,工具会做好

xhr.open("get",'http://127.0.0.1:8000/ie?t='+Date.now());

2.6 AJAX 请求状态

xhr.readyState 可以用来查看请求当前的状态

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/readyState

  • 0: 表示 XMLHttpRequest 实例已经生成,但是 open()方法还没有被调用。未初始化最开始的默认值

  • 1: 表示 open()方法调用完毕,send()方法还没有被调用,仍然可以使用 setRequestHeader(),设定 HTTP请求的头信息。

  • 2: 表示 send()方法已经执行,并且头信息和状态码已经收到。

  • 3: 表示正在接收服务器传来的 body 部分的数据。服务端已返回部分的数据

  • 4: 表示服务器数据已经完全接收,或者本次接收已经失败了

2.7 ajax请求超时或网络异常

超时:timeout、ontimeout

网络异常:onerror

2.8 ajax取消请求:abort()

2.9 AJAX请求重复发送问题解决

增加一个标识变量:

第二章:jQuery中的AJAX

2.1 get请求

$.get(url,[data],[callback],[type])

  • url : 请求的URL地址

  • data : 请求携带的参数,比如

  • callback : 载入成功时回调函数,比如function(data)

  • type : 设置响应体返回内容格式,xml, html, script, json, text, _default

2.2 post请求

$.post(url,[data],[callback],[type])

  • url : 请求的URL地址

  • data : 请求携带的参数

  • callback : 载入成功时回调函数

  • type : 设置返回内容格式,xml, html, script, json, text, _default

2.3 jQuery通用方法发送请求

ajax方法参数为一个对象,由对象属性设置请求参数

$.ajax({      
	//url(给谁发)
	url: 'http://127.0.0.1:8000/jquery-server',
	//参数
	data: {a:100, b:200},
	//请求类型
	type: 'GET',
	//响应体结果类型设置
	dataType: 'json',
	//超时时间
	timeout: 2000,
	//成功的回调
	success:function(data){
		console.log(data);
	},
	//失败的回调
	error:function(data){
		console.log('出错啦!');
	},
	//请求头信息
	headers:{
 		c:300,
		d:400
	}
});

2.4 Axios发送AJAX请求

数据返回和处理:jQuery使用的是回调函数,而axios是基于promise(then函数)

安装:npm install axios

baseURL: 对路径做简化

//配置baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';

2.4.1 get请求

axios#get(url[,config])

//配置baseURL
...

axios.get('/axios-server',{
	//url参数
	params: {
		id:100,
		vip:7
	},
	//请求头信息
	headers:{
		name: 'wdt',
		age: 20
	}
}).then(value => {
	console.log(value);
});

2.4.2 post请求

axios#post(url[,data[,config]])

第一个参数是url,第二个参数是请求体(发送的不是url查询字符串的形式,而是json格式的字符串作为数据传递),第三个参数是其他配置

//配置baseURL
...

axios.get('/axios-server',{
	username:'admin',
	password:'admin'
},{
	//url参数
	params: {
		id:200,
		vip:9
	},
	//请求头信息
	headers:{
		height: 160,
		weight: 100
	}
}).then(value => {
	console.log(value);
});

2.4.3 通用方法--Axios函数发送AJAX请求

axios()里面直接传一个对象

ajax({
	//请求方法
	method: 'POST',
	//url
	url: '/axios-server',
	//url参数
	params: {
		vip:10,
		level:30
	},
	//请求头信息
	headers:{
 		a:300,
		b:400
	}
	//请求体参数
	data: {
		username:'admin',
		password:'admin'
	}

}).then(response => {
	console.log(response);
	//响应状态码
	console.log(response.status);
	//响应状态字符串
	console.log(response.statusText);
	//响应头信息
	console.log(response.headers);
	//响应体
	console.log(response.data);
})

2.4.3 fetch函数发送AJAX请求

fetch函数属于全局对象,可以直接调用,返回的结果是promise对象,这个promise会在请求响应后被resolve,并传回Response对象

fetch( input [, init] );

  • input

    定义要获取的资源,这可能是:URL 或 一个Request对象

  • init

    可选的配置对象,包括所有对请求的设置,可选的参数有

    method、headers、body(可以是Blob,BufferSource,FormData,URLSearchParams或USVString对象,注意GET或HEAD方法的请求不能包含body信息)、mode、credentials等

                                       //可设置url参数
fetch('http://127.0.0.1:8000/fetch-server?vip=10', {
	//请求方法
	method: 'POST',
	//请求头信息
	headers:{
		name:'wdt'
	}
	//请求体
	body: 'username=admin&password=admin'

}).then(response => {
    //响应体结果不能直接获取需要return
    //如果服务端返回的是字符串
    //return response.text();
    //如果服务端返回的是json
    return response.json();
}).then(response => {
	console.log(response);
})

第三章:跨域

3.1 同源策略

同源策略(Same-Origin Policy)最早由Netscape公司提出,是浏览器的一种安全策略。

同源:当前网页的url和AJAX请求目标资源的url两者之间的 **协议、域名、端口号 **必须完全相同。

-- AJAX默认遵循同源策略:不满足同源策略没法直接发送AJAX请求

-- 违背同源策略就是跨域。

  • 同源案例:页面资源和服务端返回的数据(这里是'用户数据')都是从9000端口来的

index.html :

<script>
        const btn = document.querySelector('button');
        btn.onclick = function(){
            
            const x = new XMLHttpRequest();
            //这里因为是满足同源策略的, 所以 url 可以简写
            x.open("GET",'/data');
            //发送
            x.send();
            //
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        console.log(x.response);
            }}}}
</script>

server.js :

const express = require('express');
const app = express();

app.get('/home', (request, response)=>{
    //响应一个页面
    response.sendFile(__dirname + '/index.html');
});
app.get('/data', (request, response)=>{
    response.send('用户数据');
});

app.listen(9000, ()=>{
    console.log("服务已经启动...");
});

3.2 如何解决跨域

3.2.1 JSONP

JSONP(JSON with Padding),是一个非官方的跨域解决方案,纯粹凭借程序员的聪明

才智开发出来,只支持 get 请求。

JSONP实现原理

在网页有一些标签天生具有跨域能力,比如:img link iframe script标签。

JSONP 就是利用 script 标签的跨域能力来发送请求的。

服务端返回结果的形式是一个函数的调用,而这个函数的实参是我们想给客户端返回的结果数据,这个函数前端必须要提前声明,这就是jsonp实现跨域的原理,即返回函数调用,并且把参数放函数里,让前端的函数去处理

原生JSONP实践

在前端中输入用户名,判断用户已存在:

<html>
...
<body>
    用户名: <input type="text" id="username">
    <p></p>
    <script>
        //获取 input 元素
        const input = document.querySelector('input');
        const p = document.querySelector('p');
        
        //声明 handle 函数
        function handle(data){
            input.style.border = "solid 1px #f00";
            //修改 p 标签的提示文本
            p.innerHTML = data.msg;
        }
        
        //绑定事件
        input.onblur = function(){
            //获取用户的输入值
            let username = this.value;
            
            //向服务器端发送请求 检测用户名是否存在
            //1. 创建 script 标签
            const script = document.createElement('script');
            //2. 设置标签的 src 属性    给谁发请求
            script.src = 'http://127.0.0.1:8000/check-username';
            //3. 将 script 插入到文档中,否则浏览器不会向远端发送请求
            //把script标签插到body标签的最后
            document.body.appendChild(script);
        }
    </script>
</body>
</html>

后端代码:

app.all('/check-username',(request,response) => {
    const data = {
        exist: 1,
        msg: '用户名已存在'
    };
    //将数据转换为字符串
    let str = JSON.stringify(data);
    //返回结果
    response.end(`handle(${str})`);
});
JSONP的使用
  • 1.动态的创建一个 script 标签

    var script = document.createElement("script");

  • 2.设置 script 的 src,设置回调函数

    script.src = "http://localhost:3000/testAJAX?callback=abc";
    
    function abc(data) {
    
    	alert(data.name);
    
    };
    
  • 3.将 script 添加到 body 中

    document.body.appendChild(script);

  • 4.服务器中路由的处理

    router.get("/testAJAX" , function (req , res) {
    
    console.log("收到请求");
    
    var callback = req.query.callback;
    
    var obj = {
        name:"孙悟空", age:18
    }
    res.send(callback+"("+JSON.stringify(obj)+")");
    });
    
    jQuery 中的 JSONP

    使用jQuery发送JSONP请求时,url后面一定要补个参数callback,而且callback一定要固定写法callback=?

    callback在写的时候是个问号,但是在实际发送中是有值的。服务端可以接收到,收到后把callback这个参数的值作为调用的函数去拼接字符串。也就是说jQuery以及注册了这样的函数,从服务端回来后返回的是这个函数的调用,然后前端就可以对数据进行处理了。

...
//引进jQuery,借助BootCDN
    <script crossorigin="anonymous" src='https://cdn.bootcss.com/jquery/3.5.0/jquery.min.js'></script>
</head>
<body>
<button>点击发送 jsonp 请求</button>
    <div id="result">
    </div>
    <script>
        //绑定事件
        $('button').eq(0).click(function(){
            
            //发送jsonp请求  url 参数callback   function
            $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
                //在回调函数中对数据进行处理
                $('#result').html(`
                    名称: ${data.name}<br>
                    校区: ${data.city}
                `)
            });
        });
    </script>

服务端代码:

app.all('/jquery-jsonp-server',(request,response) => {
    const data = {
        name: '尚硅谷',
        city: ['北京','上海','深圳']
    };
    //将数据转换为字符串
    let str = JSON.stringify(data);
    //接收url中的callback参数
    let cb = request.query.callback;
    //返回结果
    response.end(`${cb}(${str})`);
});

3.2.2 CORS

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

CORS(Cross-Origin Resource Sharing),跨域资源共享。CORS 是官方的跨域解决方

案,它的特点是不需要在客户端做任何特殊的操作,完全在服务器中进行处理,支持

get 和 post 请求。跨域资源共享标准新增了一组 HTTP 首部字段(响应头),允许服务器声明哪些

源站通过浏览器有权限访问哪些资源

CORS工作原理

CORS 是通过设置一个响应头setHeader()来告诉浏览器,该请求允许跨域,浏览器收到该响应

以后就会对响应放行。

CORS的使用

主要是服务器端的设置:

router.get("/testAJAX" , function (req , res) {

//通过 res 来设置响应头,来允许跨域请求的网页url,一般写*,表示所有网页均可发送请求

//res.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");

res.set("Access-Control-Allow-Origin","*");

res.send("testAJAX 返回的响应");

});
HTTP 响应标头(首部)字段
  • Access-Control-Allow-Origin

    设置源:即哪些网页可以给服务端发请求

  • Access-Control-Expose-Headers

    设置服务端返回的结果哪些头部信息可以暴露

  • Access-Control-Max-Age

    设置预请求的结果能被缓存多久,加个时间后,每次请求直接去请求而不会做预检查

  • Access-Control-Allow-Credentials

    跨域请求时是否可携带验证信息,如cookie之类

  • Access-Control-Allow-Methods

    设置访问资源时允许使用的请求方法,默认post和get都可以,如果想要发生delete等其他请求的方法,需要加设置,比如加*,表示任何请求方法都可以运行请求

  • Access-Control-Allow-Headers

    发送的请求加了自定义请求头时,需要在响应结果中加入允许的响应头的信息,比如*,表示允许客户端在发送请求时可以发送任意的请求头,可以是预定义的也可以是自定义的。