前端学习笔记___Ajax请求

作者主页:仙女不下凡

前言介绍:以下 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!

欢迎点赞 收藏 ⭐留言 如有错误敬请指正!

学习视频地址:【尚硅谷】3小时Ajax入门到精通


一、原生Ajax

1.AJAX简介

AJAX全称为Asynchronous JavaScript And XML,就是一部的JSXML。通过AJAX可以在浏览器中向服务器发送一部请求,最大的优势:无刷新获取数据AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的刷新方式。

2.XML简介

XML可扩展标记语言XML被设计用来传递和存储数据XMLHTML类似,不同的是HTML中都是预定义标签,而是XML中没有预定义标签,全都是自定义标签,用来表示一些数据。
比如name='孙悟空'; age=18; gender='男',用XML表示。

<student>
  <name>孙悟空name>
  <age>18age>
  <gender>gender>
student>

思考: 为什么提到XML因为AJAX发送请求返回的数据格式形式就是XML格式,然后通过JavaScript转换成js对象,但是现在已经被JSON取代了。

用JSON表示:
   {"name":"孙悟空","age":"18","gender":"男"}

3.AJAX的特点

AJAX的优点: ❶可以无需刷新页面而与服务器进行通信 ❷允许你根据用户事件(click/change等)来更新部分页面内容。
AJAX的缺点: ❶没有浏览历史,不能回退 ❷存在跨域问题(同源) ❸SEO不友好。

4.AJAX的使用

HTTP协议[超文本传输协议]: 该协议详细规定了浏览器和万维网服务器之间互相通信的规则。
⏭请求报文(重点是格式与参数)

行   GET  /s?ie=utf-8  HTTP/1.1
头   Host: atguigu.com
     Cookie: name=guigu 
     Content-type: application/x-www-form-urlencoded 
     User-Agent: chrome 8.3
空行
体   空
行   POST  /s?ie=utf-8  HTTP/1.1
头   Host: atguigu.com
     Cookie: name=guigu 
     Content-type: application/x-www-form-urlencoded 
     User-Agent: chrome 8.3
空行
体   username=admin&password=admin

⏭响应报文

行   HTTP/1.1(协议)  200(响应)  ok
头  
     Content-type: text/html;  charset=utf-8
     Content-length: 2048
     Content-encoding: gzip
空行
体   ...

学习AJAX使用之前先了解一个基本框架express框架,它是一个基于Node平台的web应用开发框架,也是node第三方模块。

5. express框架的基本使用

express框架的基本使用,语法格式如下

/1.引入express/
const express = require('express');
/2.创建路由规则/
const app = express();
/3.创建路由规则  request是对请求报文的封装(自定义), response是对响应报文的封装(自定义)/
app.get('/',(request,response) => {
  /设置响应/
  response.send('HELLO EXPRESS')
});
/4.监听端口启动服务/
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...")})

客服端页面响应内容如下
前端学习笔记___Ajax请求_第1张图片

6. AJAX发送GET请求及设置参数案例

GET请求在url中传参,例如:http://127.0.0.1:8000/server?a=100&=200&c=300其中参数名为a、b、c参数分别为100、200、300

/GET.html文件/
<body>
  <button>点击发送请求button>
  <div id="result">div>

  <script>
    const btn = document.getElementByTagName('button')[0];
    btn.onclick = function({
      /1.创建对象/
      const xhr = new XMLHttpRequest();  
      /2.初始化 设置请求方法和url/
      xhr.open('GET','http://127.0.0.1:8000/server?a=100&=200&c=300');  //暂时http://127.0.0.1:8000不可以省略;
      /3.发送请求/
      xhr.send();
      /4.事件绑定 处理服务器端返回结果/
      xhr.onreadystatechange = function(){
      };  /readystate是xhr对象中的属性, 表示状态, 1 2 3 4 5,5种不同状态/
    })
  script>
body>

服务端server.js文件

const express = require('express');
const app = express();
app.get('/server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*');  //设置响应头, 设置允许跨域
  response.send('HELLO EXPRESS');  //设置响应
});
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...") })

前端学习笔记___Ajax请求_第2张图片

7. AJAX发送POST请求案例

下面为GET.html文件中的内容,页面效果当点击发送请求后,页面向服务器发送post请求,且携带参数,post请求的参数一般写在在send()请求体中,示例代码如下

<body>
  <button>点击发送请求button>
  <div id="result">div>

  <script>
    const btn = document.getElementByTagName('button')[0];
    btn.onclick = function({
      const xhr = new XMLHttpRequest();  
      xhr.open('POST','http://127.0.0.1:8000/server'); 
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');  //post特有,设置请求提类型;
      xhr.setRequestHeader('name','zhangsan');  /一般把用户身份校验信息放到这里/
      xhr.send('a=100&b=200&c=300');  //post请求设置请求参数, 参数格式也可以是a:100&b:200c:300;
      xhr.onreadystatechange = function(){
        //判断
        if(xhr.readyState === 4){
          if(xhr.status>=200 && xhr.status<300){
            result.innerHTML = xhr.response;  //处理服务端返回的结果, 这里的result是id;
          }
        }
      };
    })
  script>
body>

该文件为服务端-server.js文件,接收GET.html文件发送的请求处理后给GET.html返回响应内容,示例代码如下

const express = require('express');
const app = express();
app.post('/server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*');  //设置响应头, 设置允许跨域/
  response.send('HELLO EXPRESS');  //设置响应/
});
app.listen(8000, ()=>{ console.log("服务器已经启动, 8000端口监听中...") })

创建路由规则时可以接收任意请求类型,即post、get等都可以接收,写法如下


app.all('/server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*');  //允许跨域;
  /设置响应头, *表示所有类型的信息都可以接受/
  response.sedHeader('Access-Control-Allow-Headers','*');  
  response.send('HELLO EXPRESS');
});

8.服务器端响应JSON数据

在学习响应JSON数据时,不知道你是否产生过一些疑问,为什么要用JSON类型,客服端与服务器端之前转来转去有什么意义呢?我在该篇文章中找到了相应比较容易理解的解释:json的存在意义(json和String的区别)

⑴ 手动转换JSON数据

<body>
  <button>点击发送请求button>
  <div id="result">div>

  <script>
    const btn = document.getElementByTagName('button')[0];
    btn.onclick = function({
      const xhr = new XMLHttpRequest();  
      xhr.open('GET','http://127.0.0.1:8000/json-server'); 
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status>=200 && xhr.status<300){
            let data = JSON.parse(xhr.response);  /在这里接收到服务器传过来的JSON字符串, 手动转换/
            result.innerHTML = data.name;  /若不转换JSON字符串data.name不能用, 未来大量数据无法处理/
          }
        }
      };
    })
  script>
body>

服务端代码如下

app.all('/json-server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Ori','*'); 
  response.sedHeader('Access-Control-Allow-Ori','*');
  const data = { name:'zhangsan' };
  let str = JSON.stringify(data);  //对对象进行字符串转换
  response.send('HELLO EXPRESS');  /设置响应/
});

⑵ 自动转换JSON数据

服务端代码无变化,所以这里只写页面代码

<body>
  <button>点击发送请求button>
  <div id="result">div>

  <script>
    const btn = document.getElementByTagName('button')[0];
    btn.onclick = function({
      const xhr = new XMLHttpRequest();
      xhr.responseType = 'json';  /设置响应体数据类型, 自动转换/
      xhr.open('GET','http://127.0.0.1:8000/json-server'); 
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status>=200 && xhr.status<300){
            /因借助responseType属性所以这里直接.name就是zhangsan/
            result.innerHTML = xhr.response.name;  
          }
        }
      };
    })
  script>
body>

9.AJAX的IE缓存问题

加时间戳Date.now()解决IE缓存的问题,示例代码如下

<body>
  <button>点击发送请求button>
  <div id="result">div>

  <script>
    const btn = document.getElementByTagName('button')[0];
    const result = document.getElementById('result');
    btn.onclick = function({
      const xhr = new XMLHttpRequest();  
      /加时间戳Date.now()解决IE缓存的问题/
      xhr.open('GET','http://127.0.0.1:8000/ie?t='+Date.now()); 
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status>=200 && xhr.status<300){
            result.innerHTML = xhr.response;
          }
        }
      };
    })
  script>
body>

服务端代码如下

app.all('/ie',(request,response) => {
  response.sedHeader('Access-Control-Allow-Ori','*'); 
  response.sedHeader('Access-Control-Allow-Ori','*');
  response.send('HELLO IE');  /设置响应/
});

页面显示如图
前端学习笔记___Ajax请求_第3张图片

10.请求超时与网络异常处理

请求超时或网络异常服务器没有返回数据时,需要处理,语法格式如下

const xhr = new XMLHttpRequest(); 
xhr.timeout = 2000;  //超时设置, 超时时长为2s
xhr.ontimeout = function(){
  //这里写页面响应的内容
}
xhr.open('GET','http://127.0.0.1:8000/ie'); 
xhr.send();
xhr.onreadystatechange = function(){};

11.取消请求

调用abort()方法就可以取消请求,示例代码如下

<body>
  <button>点击发送button>
  <button>点击取消button>
  <script>
    const btns = document.getElementByTagAll('button');
    let xhr = null;
    btns[0].onclick = function({
      xhr = new XMLHttpRequest();  
      xhr.open('GET','http://127.0.0.1:8000/ie'); 
      xhr.send();
    })
    btns[1].onclick = function(){
      xhr.abort();  /取消请求/
    }
  script>
body>

12.请求重复发送

思考: 若向服务器中重复发送相同的不必要请求,其实我们只请求一次就可以,这种情况怎么办呢?下面我们就通过标识变量去解决这个问题,示例代码如下

<body>
  <button>点击发送button>
  <script>
    const btn = document.getElementByTagName('button');
    let xhr = null;
    let isSending = false;  /标识变量/
    btn.onclick = function({
      if(isSending)xhr.abort();  //如果正在发送, 则取消该请求, 创建一个新的请求
      xhr = new XMLHttpRequest();
      isSending = true;  //修改标识变量的值;
      xhr.open('GET','http://127.0.0.1:8000/ie'); 
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4) isSending = false;
      }
    })
  script>
body>

13.jquery发送AJAX请求

下面演示在jquery框架中发送ajax请求的方法,示例代码如下

<body>
  <button class="btn">GETbutton>
  <button class="btn">POSTbutton>
  <button class="btn">通用型方法ajaxbutton>
  <script>
    $('button').eq(0).click(function(){
      $.get('http://127.0.0.1:8000/jquery-server', {a:100,b:200}, function(data){
        console.log(data);  //控制台结果为{name:'zhangsan'}
      },'json');  /这里标识响应体为json格式数据/
    })
    $('button').eq(1).click(function(){
      $.post('http://127.0.0.1:8000/jquery-server', {a:100,b:200}, function(data){
        console.log(data);  //控制台结果为{name:'zhangsan'}
      },'json')
    });

    /通用型发送ajax请求/
    $('button').eq(2).click(function(){
      $.ajax({
        url: 'http://127.0.0.1:8000/jquery-server',
        data: {a:100,b:200},  /参数/
        type: 'GET',  /类型/
        dataTaye: 'json',  /响应体数据类型/
        success: function(data){},  /成功的回调/
        timeout: 2000,  /超时时间/
        error: function(data){},  /失败的回调/
        headers: {c:300,d:400},  /头信息/
      })
    })
  script>
body>

服务器端代码

app.all('/jquery-server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*'); 
  response.sedHeader('Access-Control-Allow-Headers','*'); 
  const data = {name:'zhangsan'};
  response.send(JSON.stringify(data));  /设置响应/
});

总结:jquery框架中通用型ajax发送请求功能性更加强一些,但是以上两种方式代码更加简洁,可以根据实际的应用选择具体写法。

14.Axios发送AJAX请求

使用Axios发送ajax请求时,需要安装Axios或者直接npm install axios引入。

<head>
  <script src="引入的axios的文件包">script>  //这里也可以直接用npm install axios直接安装
head>
<body>
  <button>GETbutton>
  <button>POSTbutton>
  <button>AJAXbutton>
  <script>
    const btns = document.querySelectorAll('button');

    axios.defaults.baseURL = 'http://127.0.0.1:8000';  /配置baseURL, 下面的地址就可以省略了/
    btns[0].onclick = function(){
      axios.get('/axios-server',{
        params: {id:100, vip:7},  /url参数/
        headers: {name:'lisi',age:25},  /请求头信息/
        ....
      }).then(value=>{});  /它的请求是在.then()中处理的,跟ajax不一样/
    }
    btns[1].onclick = function(){
      axios.get('/axios-server',{这是请求体},{
        params: {id:200, vip:9},  /url参数/
        headers: {name:'lisi',age:18},  /请求头信息/
      }).then(value=>{});  /它有三个参数, 另外它的请求是在.then()中处理的,跟ajax不一样/
    }
    
    btns[2].onclick = function(){
      axios({
        method: 'GET',  /请求类型/
        url: '/axios-server',  
        params: {},  /url参数/
        headers: {},  /头信息/
        data: {}  /请求体信息/
      }).then(response=>{
        console.log(response.status);  /响应状态码/
        console.log(response.statusText);  /响应状态字符串/
        console.log(response.data);  /响应体/
      })/它的格式跟jquery通用型ajax相似, 非常简洁,请求响应结果也是在.then()中处理/
    }
  script>
body>

服务端代码如下

app.all('/axios-server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*'); 
  response.sedHeader('Access-Control-Allow-Headers','*'); 
  const data = {name:'zhangsan'};
  response.send(JSON.stringify(data));  /设置响应/
});

15.使用fetch函数发送AJAX请求(了解)

fetch() 属于全局对象,可以直接调用,返回结果是promise对象,在前端发送Ajax中使用axios的非常多,但是使用fetch()使用的比较少,在这里fetch()作为了解进行学习。

//该项目中已经npm install axios直接安装axios
<body>
  <button>AJAX请求button>
  <script>
    const btns = document.querySelector('button');

    btns.onclick = function(){
      fetch.get('http://127.0.0.1:8000/fetch-server?id=3',{  //url参数直接写在后面
        method: 'POST',  /请求方法/
        headers: {},  /请求头/
        body: 'username=zhangsan&password=admin',  /请求体, 注意请求体格式/
      }).then(response=>{
        return response.json();  /这里需要用return返回响应结果并且在下一个.then()中处理/
        //如果服务器返回的不是json字符串用return response.text()处理
      }).then(response=>{/这里的response就是响应结果{name:'zhangsan'}, 别和上面的response混淆呦/}); 
    }
  script>
body>

服务端代码如下

app.all('/fetch-server',(request,response) => {
  response.sedHeader('Access-Control-Allow-Origin','*'); 
  response.sedHeader('Access-Control-Allow-Headers','*'); 
  const data = {name:'zhangsan'};
  response.send(JSON.stringify(data));  /设置响应/
});

二、同源策略

同源策略: 最早由Netscape公司提出,是浏览器的一种安全策略。
同源: 指协议、域名、端口号必须完全相同,违背同源策略就是跨域。
下面用一段代码演示什么是同源发送请求,点击按钮后/home页面获取到/data中的数据,启动服务器后找到打开http://127.0.0.1:9000/home页面呈现如下图
前端学习笔记___Ajax请求_第4张图片
服务器端代码如下

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("服务器已经启动....") });

.html页面代码如下

<body>
  <h1>.html页面h1>
  <button>AJAX请求button>
  <script>
    const btns = document.querySelector('button');
    btns.onclick = function(){
      const xhr = new XMLHttpRequest();
      /因为这里是同源策略, 所以url可以简写/
      xhr.open('GET', '/data');
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status>=200&&xhr.status<300) console.log(xhr.response);
        }
      }
    }
  script>
body>

三、非同源策略(跨域)

1.什么是跨域(非同源)

非同源(跨域): 指协议、域名、端口号其中有一样或多样不相同就是跨域。但是非同源会有很多限制。

2.非同源限制

【1】无法读取非同源网页的Cookie、LocalStorage 和 IndexedDB
【2】无法接触非同源网页的DOM
【3】无法向非同源地址发送AJAX请求。

在实际的项目中我们常常遇到跨域的情况,为了解决这些问题,所以下面讨论两种"跨域"的解决方案:JSONPCORS(其实还有其他的办法)。

3.跨域解决方案-JSONP

⑴ jsonp的实现原理

JSONP怎么工作呢?JSONP利用script标签的跨域能力来发送请求。

下面用一段实例代码演示JSONP的实现原理,下面代码运行地址flie://src/index.html但是引入的是http协议的http://127.0.0.1:8000/jsonp-server所以为跨域。

<body>
  <div id="result">div>
  <script>
    function handle(data){
      const result = document.querySelectorId('result');
      result.innerHTML = data.name;
    }
  script>
  <script src="http://127.0.0.1:8000/jsonp-server">script>
body>
//服务器代码
app.all('/jsonp-server',(request,response) => {
  const data = {name:'zhangsan'};
  let str = JSON.stringify(data);
  response.end(`handle(${str})`);
});

JSONP缺点: 但是JSONP是一个非官方的跨域解决方案,而且只支持get请求。

⑵ 原生jsonp实践

下面用一个简单的业务需求来演示原生jsonp的使用。

需求: ❶当在input输入框中输入失去焦点之后发送ajax请求❷将跨域服务器中的内容响应到页面上。

<body>
  用户名:<input type="text" id="username">
  <p>p>
  <script>
    const input = document.querySelector('input');
    const p = document.querySelector('p');
    function handle(data){
      p.innerHTML = data.msg;
    };  //声明handle函数, 与服务器保持一致
    input.onblur = function(){
      let username = this.value;
      const script = document.createElement('script');  /1.创建script标签/
      script.src = 'http://127.0.0.1:8000/check-username';  /2.设置script标签/
      document.body.appendChild(script);  /3.将script标签插入文档/
    };
  script>
body>
//服务器代码
app.all('/check-username',(request,response) => {
  const data = {msg:'用户名已经存在'};
  let str = JSON.stringify(data);
  response.end(`handle(${str})`);   //服务器调用handle函数
});

好了以上代码就实现了跨域的jsonp请求。

⑶ jQuery发送jsonp请求

<body>
  <button>发送jsonp请求button>
  <div id="result">div>
  <script>
    $('btton').eq(0).click(function(){
      /固定jsonp传参数用callback, jquery中的发送的callback?直接就转换成参数了,可以自己运行一下/
      $.getJSON('http://127.0.0.1:8000/jquery-jsonp-server?callback=?', function(data){
        $('#result').html('名称: ${data.name}
'
) }) });
script> body>
//服务器代码
app.all('/jquery-jsonp-server',(request,response) => {
  const data = {name:'zhangsan'};
  let str = JSON.stringify(data);
  let cb = request.query.callback;  /这样就取到上面自动转换的callback参数了/
  response.end(`${cb}(${str})`); 
});

4.跨域解决方案-CORS

CORS(跨域资源共享): 是官方的跨域解决方案,默认支持getpost请求(需要其他请求方式自己可以设置这里不展开),跟上面JSONP不同的是CORS是通过设置一个响应头来告诉浏览器(上面其实我已经用到啦),该请求允许跨域,浏览器收到该响应就会对响应放行。

CORS的使用: 主要是服务器端的设置router.get("/testAJAX",function(req,res){})

<body>
  <button>发送jsonp请求button>
  <div id="result">div>
  <script>
    const button = document.querySelector('button');
    function handle(data){
      p.innerHTML = data.msg;
    };  //声明handle函数, 与服务器保持一致
    button.onclick = function(){
      const xhr = new XMLHttpRequest;
      xhr.open("GET","http://127.0.0.1:8000/cors-server");
      xhr.send();
      xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
          if(xhr.status>=200 && xhr.status<300){
            response.setHeader("Access-Control-Allow-Origin","*");  /这就可以啦/
          }
        }
      }
    };
  script>
body>
//服务器代码
app.all('/cors-server',(request,response) => {
  response.send(hello cors); 
});

其实除了Access-Control-Allow-Origin响应头以外还有其他的响应头,有需要的可以自行了解一下。

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