新手咋地

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ajax

一、ajax基础

ajax概述

浏览器提供的一套方法,可以实现页面无刷新更新数据

Ajax应用场景

1、页面上拉加载更多数据

2、列表数据无刷新分页

3、表单离开焦点表单验证

4、搜索框提示文字下拉列表

Ajax运行原理及实现

Ajax的实现步骤

1、创建ajax对象

var xhr = new XMLHttpRequest();

2、告诉Ajax请求地址以及请求方式

xhr.open('get','http://www.example.com');

3、发送请求

xhr.send();

4、获取服务器端与客户端的响应数据

xhr.onload = function (){
   console.log (xhr.responseText);
}

请求方式传递

GET请求方式

xhr.open('get','http:www.example.com?name=zhangsan&age=20');

POST请求方式

xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('name=zhangsan&age=20');

请求参数的格式

1.application/x-www-form-urlencoded

name=zhangsan&age=

2.application/json

{name:'zhangsan',age:'20',sex:'男'}

在请求头中指定Content-Type属性的值是application/json,告诉服务器端当前请求参数的格式是json

JSON.stringify()//讲json对象转换成json字符串

注意:get请求是不能提交json对象数据格式的,传统网站表单提交也是不支持json对象数据格式的。

获取服务器端的相应

Ajax状态码

在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过成每一个步骤都会对应一个数值,这个数值就是ajax状态码

0:请求未初始化(还没调用open())

1:请求已经建立,但是还没有发送(还没有调用send())

2:请求已经发送

3:请求正在处理中,响应中有部分数据可以用了

4:相应已经完成,可以获取并使用服务器的响应了

xhr.readyState//获取 Ajax状态码

onreadystatechange 事件当Ajax状态码变化时将自动触发该事件

两种获取方式

1.onload事件

        var xhr = new XMLHttpRequest();
       xhr.open('get', 'dome1.php')
       xhr.send();
       xhr.onload = function () {
           
      }

2onreadystatechange事件

var xhr = new XMLHttpRequest();
xhr.open('get','http//localhost:3000/readystate')
xhr.onreadystatechange = function(){
   if(xhr.readyState == 4){
       
  }
}
xhr.send();

两种获取服务器端相应的区别

区别描述onload事件onreadystatechange事件
是否兼容IE低版本 不兼容 兼容
是否需要判断Ajax状态码 不需要 需要
被调用次数 一次 多次

如果不需要兼容建议使用onload事件,代码更简单,并且只会调用一次

Ajax错误处理

1、网络畅通,服务器端能接收到请求,服务器端返回的 结果不是预期结果。

可以判断服务器返回的状态码,分别进行处理xhr.status获取的状态码

2、网络畅通,服务器端没有收到请求,返回404状态码

检查请求地址是否错误

3、网络畅通,服务器端能接收到请求,服务器端返回500状态码

服务器端错误,找后端程序员进行沟通

4、网络中断,请求无法发送到服务器

会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理*

xhr.onload = function(){
   //当网络中断会触发onerror事件
   xhr.onerror = function(){
       alert('网络中断,无法发送Ajax请求')
  }
}
//Ajax状态码:表示Ajax请求过程状态 是ajax对象返回的
//Http状态码:表示请求的处理结果 是服务器端返回的

低版本IE浏览器的缓存问题

问题:在低版本的IE浏览器中,在请求地址不发生改变的情况下,只有第一次请求才会发送给服务器,后续都会从浏览器的缓存中获取结果,即使服务器端的 数据更新了,服务器依然拿到的是缓存中的旧数据。

解决方案:在请求的后面请求参数,保证每一次请求的值不相同

xhr.open('get','http://www.example.com?t='+Math.random());

二、Ajax异步编程

同步异步概述

同步:一个人 同一时间只能做一个事情,只有一个事情做哇才能做另一件事情

异步:一个人一件事情做了一半,转而去做其他事情,再回头继续做其他未完成的事情

落实到代码上,就是落实到代码上,就是异步代码虽然需要花费时间去执行,但程序不会等待异步代码执行完成后再继续执行后续代码,而是直接执行后续代码当后续代码执行完成后再回头看异步代码是否返回结果,如己有返回结果,再调用事先准备好的回调函数处理异步代码执行的结果。

console.log('before');
setTimeout(
() =>{ console.log('last');
  },2000);
console.log('after');

Ajax封装

问题:发送一次请求过多,发送多i请求代码冗余且重复。

解决方案:将请求代码封装到函数中,发送请求时调用函数即可。

ajax({
   type:'get',
   url:'http://www.example.com',
   success: function (date) {
       console.log(date);
  }
})

例子1

function ajax (options) {
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //配置ajax对象
   xhr.open(options.type,option.url);
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
       options.success(xhr.responseText);
  }
}
ajax({
   //请求方式
   type:'get',
   //请求地址
   url:'http://localhost:3000/first',
   success: function (date) {
       console.log('这里是success函数' + date)
  }
})

拓展:

再发送请求的时候向服务器传递参数:

请求番薯要考虑的问题

1.请求参数位置的问题

将请求参数传递到ajax函数内部,在函数内部根据请求方式的不同将请求参数放置在不同的位置 get放在请求地址的后面 post放在send方法中

2.请求参数格式的问题

application/ x -WWW- form- urlencoded 参数名称=参数值&参数名称=参数值 name=zhangsan&age=20 application/ json {name:' zhangsan', age: 20}

如果传递的是第一种类型很有可能需要将它转换成第二种,如果是第二种,很有可能需要转换成第一种,显然第二种转换成第一种更为方便

1.传递对象数据类型对于函数的调用者更加友好 2.在函数内部对象数据类型转换为字符串数据类型更加方便

例子2

function ajax (options) {
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //拼接请求参数的变量
   var params = '';
   for(var attr in options.data) {
       //将参数转换成字符串格式
       params += attr + '=' +options.data[attr] + '&';//因为attr是一个变量,对象后面不能直接.变量,所以用options.data[attr]
  }
   //将参数后面的&截取掉
   //将截取的结果重新赋值给params
   parms = params.substr(0,params.length-1);
   //判断请求方式
   if (potions.type == 'get'){
       options.url = options.url + '?' +params;
  }
   //配置ajax对象
   xhr.open(options.type,option.url);
   if (options.type == 'post') {
       //设置请求参数格式的类型
       xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
       xhr.send(params);
  }
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
       options.success(xhr.responseText);
  }
}
ajax({
   //请求方式
   type:'get',
   //请求地址
   url:'http://localhost:3000/first',
   data: {
       name: 'zhangsan',
       age: 20
  },
   success: function (data) {
       console.log('这里是success函数' + date)
  }
})

完善:

如果传递参数的人传递json

例子3

function ajax (options) {
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //拼接请求参数的变量
   var params = '';
   for(var attr in options.data) {
       //将参数转换成字符串格式
       params += attr + '=' +options.data[attr] + '&';//因为attr是一个变量,对象后面不能直接.变量,所以用options.data[attr]
  }
   //将参数后面的&截取掉
   //将截取的结果重新赋值给params
   parms = params.substr(0,params.length-1);
   //判断请求方式
   if (potions.type == 'get'){
       options.url = options.url + '?' +params;
  }
   //配置ajax对象
   xhr.open(options.type,option.url);
   if (options.type == 'post') {
       //用户希望向服务器传递的请求参数的类型
       var contentType = options.header['Content-Type']//因为带了-,所以必须是字符串不然不合法,用了options.header['Content-type']
       //设置请求参数格式的类型
       xhr.setRequestHeader('Content-Type','contentType');
       //判断用户希望的请求参数格式的类型
       //如果类型为json
       if (contentType == 'application/json'){
           //向服务器端传递json数据格式的参数
           xhr.send(JSON.striongify(oprions.data));
      }else {
           //向服务器端传递普通类型的请求参数
           xhr.send(params)
      }
       xhr.send(params);
  }
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
       options.success(xhr.responseText);
  }
}
ajax({
   //请求方式
   type:'get',
   //请求地址
   url:'http://localhost:3000/first',
   data: {
       name: 'zhangsan',
       age: 20
  },
   header:
   success: function (data) {
       console.log('这里是success函数' + date)
  }
})

完善:

服务器响应成功与失败分离:

function ajax (options) {
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //拼接请求参数的变量
   var params = '';
   for(var attr in options.data) {
       //将参数转换成字符串格式
       params += attr + '=' +options.data[attr] + '&';//因为attr是一个变量,对象后面不能直接.变量,所以用options.data[attr]
  }
   //将参数后面的&截取掉
   //将截取的结果重新赋值给params
   parms = params.substr(0,params.length-1);
   //判断请求方式
   if (potions.type == 'get'){
       options.url = options.url + '?' +params;
  }
   //配置ajax对象
   xhr.open(options.type,option.url);
   if (options.type == 'post') {
       //用户希望向服务器传递的请求参数的类型
       var contentType = options.header['Content-Type']//因为带了-,所以必须是字符串不然不合法,用了options.header['Content-type']
       //设置请求参数格式的类型
       xhr.setRequestHeader('Content-Type','contentType');
       //判断用户希望的请求参数格式的类型
       //如果类型为json
       if (contentType == 'application/json'){
           //向服务器端传递json数据格式的参数
           xhr.send(JSON.striongify(oprions.data));
      }else {
           //向服务器端传递普通类型的请求参数
           xhr.send(params)
      }
       xhr.send(params);
  }
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
//当http状态码等于200的时候
       if (xhr.status == 200) {
      //请求成功 调用处理成功情况的函数
           options.success(xhr.responseText, xhr);
      }else {
           //请求失败 调用处理失败情况的函数
           options.error(xhr.responseText, xhr);
      }
  }
}
ajax({
   //请求方式
   type:'get',
   //请求地址
   url:'http://localhost:3000/first',
   data: {
       name: 'zhangsan',
       age: 20
  },
   header: {
       'Content-Type': 'application/x-www-form-urlencoded'
  },
   success: function (data,xhr) {
       console.log('这里是success函数' + data)
  }
error: function (data,xhr){
       console.log('这里是error函数' + data)
  }
})

完善:

将json字符串转换成json对象

function ajax (options) {
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //拼接请求参数的变量
   var params = '';
   for(var attr in options.data) {
       //将参数转换成字符串格式
       params += attr + '=' +options.data[attr] + '&';//因为attr是一个变量,对象后面不能直接.变量,所以用options.data[attr]
  }
   //将参数后面的&截取掉
   //将截取的结果重新赋值给params
   parms = params.substr(0,params.length-1);
   //判断请求方式
   if (potions.type == 'get'){
       options.url = options.url + '?' +params;
  }
   //配置ajax对象
   xhr.open(options.type,option.url);
   if (options.type == 'post') {
       //用户希望向服务器传递的请求参数的类型
       var contentType = options.header['Content-Type']//因为带了-,所以必须是字符串不然不合法,用了options.header['Content-type']
       //设置请求参数格式的类型
       xhr.setRequestHeader('Content-Type','contentType');
       //判断用户希望的请求参数格式的类型
       //如果类型为json
       if (contentType == 'application/json'){
           //向服务器端传递json数据格式的参数
           xhr.send(JSON.striongify(oprions.data));
      }else {
           //向服务器端传递普通类型的请求参数
           xhr.send(params)
      }
       xhr.send(params);
  }
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
       //获取响应头中的数据
       var contentType = xhr.getResponseHeader('Content-Type');
       //服务器端返回的数据
       var responseText = xhr.responseText;
       
       //如果响应类型中包含application/json
       if (contentType.includes(application/json)) {
           //将json字符串转换成json对象
           responseText = JSON.parse(resonseText);
      }
//当http状态码等于200的时候
       if (xhr.status == 200) {
      //请求成功 调用处理成功情况的函数
           options.success(responseText, xhr);
      }else {
           //请求失败 调用处理失败情况的函数
           options.error(responseText, xhr);
      }
  }
}
ajax({
   //请求方式
   type:'get',
   //请求地址
   url:'http://localhost:3000/first',
   data: {
       name: 'zhangsan',
       age: 20
  },
   header: {
       'Content-Type': 'application/x-www-form-urlencoded'
  },
   success: function (data,xhr) {
       console.log('这里是success函数' + data)
  }
error: function (data,xhr){
       console.log('这里是error函数' + data)
  }
})

完善:

如果说用户每次使用都需要传递没用的变量,会很麻烦,那么可以在函数内封装一个对象,对象中的参数就是默认值,如果用户传递参数那么用用户传递的参数,如果没传递用默认值。

function ajax (options) {
       //存储的是默认值
   var defaults = {
       type: 'get',
       url: '',
       data:{},
       header: {
       'Content-Type': 'application/x-www-form-urlencoded'
  },
    success: function(){},
       error: function(){}
  }
   //使用options对象中的属性覆盖defaults对象中的属性
   Object.assign(defaults,options);
   //创建ajax对象
   var xhr = new XMLHttpRequest();
   //拼接请求参数的变量
   var params = '';
   for(var attr in defaults.data) {
       //将参数转换成字符串格式
       params += attr + '=' +defaults.data[attr] + '&';//因为attr是一个变量,对象后面不能直接.变量,所以用defaults.data[attr]
  }
   //将参数后面的&截取掉
   //将截取的结果重新赋值给params
   parms = params.substr(0,params.length-1);
   //判断请求方式
   if (potions.type == 'get'){
       defaults.url = defaults.url + '?' +params;
  }
   //配置ajax对象
   xhr.open(defaults.type,defaults.url);
   if (defaults.type == 'post') {
       //用户希望向服务器传递的请求参数的类型
       var contentType = defaults.header['Content-Type']//因为带了-,所以必须是字符串不然不合法,用了options.header['Content-type']
       //设置请求参数格式的类型
       xhr.setRequestHeader('Content-Type','contentType');
       //判断用户希望的请求参数格式的类型
       //如果类型为json
       if (contentType == 'application/json'){
           //向服务器端传递json数据格式的参数
           xhr.send(JSON.striongify(defaults.data));
      }else {
           //向服务器端传递普通类型的请求参数
           xhr.send(params)
      }
       xhr.send(params);
  }
   //发送请求
   xhr.send();
   //监听xhr对象下面的onload事件
   //当xhr对象接收完响应数据后触发
   xhr.onload = function () {
       //获取响应头中的数据
       var contentType = xhr.getResponseHeader('Content-Type');
       //服务器端返回的数据
       var responseText = xhr.responseText;
       
       //如果响应类型中包含application/json
       if (contentType.includes(application/json)) {
           //将json字符串转换成json对象
           responseText = JSON.parse(resonseText);
      }
//当http状态码等于200的时候
       if (xhr.status == 200) {
      //请求成功 调用处理成功情况的函数
           options.success(responseText, xhr);
      }else {
           //请求失败 调用处理失败情况的函数
           options.error(responseText, xhr);
      }
  }
}
//调用ajax函数
ajax({
   //请求地址
   url:'http://localhost:3000/first',
   success: function (data,xhr) {
       console.log('这里是success函数' + data)
  }

})

三、FormData

FromData对象的作用

1.模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求数据参数的格式

2.异步上传二进制文件

FromData对象的使用

1.准备HTML表单

<form id="form">
   <input type="text" name="username">
   <input type="password" name="password">
   <input type="button" id="btn">
</form>

一定要有name属性,因为需要将表单参数传递给服务器端,name做为请求数据的属性名称

2.将HTML表单准华为formData对象

FormData是一个构造函数

var form = document.getElementById("form");
var formData = new FormData(form);

3.提交表单对象

xhr.send(formData)

实例

<form id="form">
   <input type="text" name="username">
   <input type="password" name="password">
   <input type="button" id="btn">
</form>
<script>
   //获取按钮
var btn = document.getElementById('btn')
   //获取表单
   var form =document.getElementById('form');
   //为按钮添加点击事件
   btn.onclick = function(){
       //将普通的html表单转换成表单对象
       var formData = new FormData(form);
       //创建ajax对象
       var xhr = new XMLHttpRequest();
       //对ajax对象进行配置
       xhr.open('post','http://example.com');
       //发送ajax请求
       xhr.send(formData);
       //监听xhr对象下面的onload事件
       xhr.onload = function(){
           //对象http状态码进行判断
           if(xhr.status == 200){
               console.log(xhr.responseText);
          }
      }
  }
</script>

FormData对象的实例方法

  1. 获取表单对象中属性的值

    formDate.get('key');
  2. 设置表单对象中属性的值

    formDate.set('key','value');
  3. 删除表单对象中属性的值

    formDate.delete('key');
  4. 向表单对象中追加属性值

    formDate.append('key','value');

    注意:set方法与append方法的区别是,在属性名已存在的情况下,set会覆盖已有键名的值,append会保留两个值

FormData二进制文件上传

客户端的核心代码

<input type="file" id="file">
var file = document.getElementById('file');
//当用户选择文件时
file.onchange = function(){
   //创建空表单对象
var formData = new FormData();
//将用户选择的二进制文件追加到表单对象中
   formData.append('attrName',this.files[0]);
   //配置ajax对象,请求方式必须为post
   xhr.open('post','www.example.com');
   xhr.send(formData);
   
}

FormData文件上传进度展示

//用户选择文件时
file.onchange = function(){
   //文件上传过程中持续出发onprogress事件
   xhr.upload.onprogress = function(ev){
       //当前文件上传大小/总文件大小 在将结果转换为百分数
       //将结果赋值给进度条的宽度属性
       bar.style.width = (ev.loaded / ev.total) * 100 +'%';
  }
}

FormData文件上传图片即时预览

在我们将图片上传到服务器端以后,服务器端通常都会将图片地做为响应数据传递到客户端,客户端可以从响应数据中获取图片地址,然后将图片再显示在页面中。

核心代码

if (xhr.status == 200) {
//将服务器端返回的数据显示在控制台中
var result = JSON. parse (xhr●responseText);
//动态创建img标签
var img = document . createElement( ' img ');
//给图片标签设置src属性
img.src = result.path;
//当图片加载完成以后
img.onload = function () {
//将图片显示在页面中
box.appendChild(img) ;
}
}

具体服务器端操作以后补充

 

四、同源政策

Ajax请求限制

Ajax只能向自己的服务器发送请求。比如现在有一个A网站、有一一个B网站,A网站中的HTML文件只能向A网站服务器中发送Ajax请求, B网站中的HTML文件只能向B网站中发送Ajax请求,但是A网站是不能向B网站发送Ajax请求的,同理, B网站也不能向A网站发送Ajax请求。

什么是同源

如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一一个源,其中只要有一 个不相同,就是不同源。

同源政策的目的

同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是指A网站在客户端设置的Cookie, B网站是不能访问的。

随着互联网的发展,同源政策也越来越严格,在不同源的情况下其中有一项规定就是无法向非同源地址发送Ajax请求,如果请求,浏览器就会报错。

使用JSONP解决同源限制问题

jsonp是json with padding的缩写,它不属于Ajax请求,但它可以模拟Ajax请求。

  1. 将不同源服务器端的请求地址写在script标签的src属性中

    <script src="www.example.com"></script>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>

    请求地址必须返回合法的JavaScript代码

  2. 服务器端相应的数据必须是一个函数的调用,真正发送给客户端的数据需要作为函数调用的参数

    const data ='fn({name:"张三",age:"20"})';
    res.send(data);
  3. 在客户端全局作用域下定义函数fn

    function fn (data){}

    函数定义代码要写在script标签上面,并且要在全局作用域下定义

  4. 在fn函数内部对服务器端返回的数据进行处理

    function fn (data) { console.log(data); }

 以后具体jsonp如何实现,等学完node回来补充更新

posted on 2021-10-20 20:00  新手咋地  阅读(118)  评论(1)    收藏  举报