AJAX(一)HTTP协议(请求响应报文),AJAX发送请求,请求问题处理

文章目录

  • 一、AJAX
  • 二、HTTP协议
    • [1. 请求报文](#1. 请求报文)
    • [2. 响应报文](#2. 响应报文)
  • 三、AJAX案例准备
    • [1. 安装node](#1. 安装node)
    • [2. Express搭建服务器](#2. Express搭建服务器)
    • [3. 安装nodemon实现自动重启](#3. 安装nodemon实现自动重启)
  • 四、AJAX发送请求
    • [1. GET请求](#1. GET请求)
    • [2. POST请求](#2. POST请求)
      • [(1) 配置请求体](#(1) 配置请求体)
      • [(2) 配置请求头](#(2) 配置请求头)
    • [3. 响应JSON数据的两种方式](#3. 响应JSON数据的两种方式)
      • [(1) 手动,JSON.parse()](#(1) 手动,JSON.parse())
      • [(2) 设置xhr.responseType](#(2) 设置xhr.responseType)
  • 五、AJAX请求问题处理
    • [1. IE浏览器缓存的问题](#1. IE浏览器缓存的问题)
    • [2. AJAX请求超时与网络异常](#2. AJAX请求超时与网络异常)
    • [3. 手动取消请求](#3. 手动取消请求)
    • [4. 请求重复发送的问题](#4. 请求重复发送的问题)

ajax在网页不刷新的情况下发送http请求,获取http响应。

可实现懒加载,用则加载,不用则不加载

一、AJAX

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

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

优点

  1. 可以无需刷新页面而与服务器端进行通信。
  2. 允许根据用户事件来更新部分页面内容。

缺点

  1. 没有浏览历史,不能回退
  2. 存在跨域问题(同源)
  3. SEO (Search Engine Optimization,搜索引擎优化) 不友好。网页当时的内容爬虫是爬不到的,比如要在商品列表,爬取某一商品的详细信息。此时页面并没有这个详细信息,详细信息是点击商品之后通过ajax请求获取到的。

二、HTTP协议

HTTP(hypertext transport protocol)协议(超文本传输协议),协议详细规定了浏览器和万维网服务器之间互相通信的规则。这个协议其实就是一种规定,通信都按着这个规定来。

1. 请求报文

客户端向浏览器发送的内容叫请求报文,请求报文包括四部分:

①请求行 : 请求类型(GET/POST) + URL地址 + HTTP协议版本(HTTP/1.1)

②请求头:(内容不用记,记得格式是键值对就行)

javascript 复制代码
Host: atguigu.com
Cookie: name=guigu
Content-type: application/x-www-form-urlencoded
User-Agent: chrome 83

③空行:必须要有的

④请求体:若为GET请求则为空。若为POST请求,可以不为空

2. 响应报文

浏览器向客户端返回的结果叫响应报文,也包括四部分:

①响应行 : HTTP协议版本(HTTP/1.1) + 响应状态码(200) + 响应状态字符串(ok)

②响应头:(格式与请求头一样)

javascript 复制代码
Content-Type: text/html;charset=utf-8
Content-length: 2048
Content-encoding: gzip

③空行:必须要有的

④响应体:服务器的返回结果

三、AJAX案例准备

1. 安装node

学vue的时候安装过,具体见博客:Vue安装脚手架及一些配置

2. Express搭建服务器

用ajax向服务器发请求。我们就用express搭建一个简易的服务器。
(1) 先初始化一下项目

ajax文件夹下执行下面的命令,生成package.json文件

javascript 复制代码
npm init --yes

(2) 安装express

在ajax文件夹下执行命令,安装express

javascript 复制代码
npm i express

(3) 配置服务器

创建文件夹AJAX/express.js:

javascript 复制代码
//  1. 引入express
const express = require('express')
// 2. 创建应用对象
const app = express();
// 3. 创建路由规则
// request 是对请求报文的封装,response 是对响应报文的封装
app.get('/server', (request, response) => {
  // 设置响应头 设置允许跨域,(跨域这里先这样设置)
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 设置响应体
  response.send('HELLO AJAX')
})

// 4. 监听端口服务器
app.listen(8000, () => {
  console.log('服务已经启动,8000端口监听中....');
})

目前的目录结构为:

(4) 启动服务器

注意要在该js文件所在的文件夹下打开终端,否则运行命令时找不到这个js文件

在终端输入命令,启动服务器,

网页运行测试:

3. 安装nodemon实现自动重启

每次修改服务器的js文件都要重启服务器,很麻烦,安装nidemon可以自动重启服务器。

安装:npm install -g nodemon

启动服务器:nodemon 文件名.js

四、AJAX发送请求

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

1. GET请求

在服务器文件中配置get响应接口,再往这个接口发请求。
server.js:

javascript 复制代码
app.get('/server', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 设置响应体
  response.send('HELLO AJAX')
})

页面结构

javascript 复制代码
  // 获取元素
  const btn = document.querySelector('#btn')
  const div = document.querySelector('#content')
  // 监听点击事件
  btn.addEventListener('click', () => {
    // 1. 创建对象
    const xhr = new XMLHttpRequest();
    // 2. 初始化,设置请求方法和url
    xhr.open('GET', 'http://localhost:8000/server');
    // 3. 发送请求
    xhr.send()
    // 4. 事件绑定处理服务器返回的结果
    // readystate是xhr属性,表示状态0,1,2,3,4 当状态改变时这个函数被调用
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        // 判断响应码 200 404 403
        // 响应码是2xx,则请求成功
        if (xhr.status >= 200 && xhr.status < 300) {
          console.log('状态码:', xhr.status);
          console.log('状态字符串:', xhr.statusText);
          console.log('响应头:', xhr.getAllResponseHeaders());
          console.log('响应体:', xhr.response);
          // 将响应结果渲染到页面
          div.innerHTML = xhr.response
        }
      }
    }
  })

四个状态值分别表示:
0:未初始化;1:open方法已被调用;2:send方法已被调用
3:服务端返回部分结果;4:服务端返回全部结果;

GET请求携带参数的方式:url?a=10&b=20&c=30,参数会成为请求地址的一部分

2. POST请求

(1) 配置请求体

POST请求设置请求体在send()函数里设置,可配置一些请求参数。这样参数不会成功地址URL的一部分。请求体里的内容格式可以随便写,前提是服务端要有对应的处理方式。

javascript 复制代码
// 发送POST请求
btnPost.addEventListener('click', () => {
  // 1. 创建对象
  const xhr = new XMLHttpRequest();
  // 2. 初始化,设置请求方法和url
  xhr.open('POST', 'http://localhost:8000/server');
  // 3. 发送请求 请求体可以是任意形式
  // xhr.send(1234567)
  // xhr.send('a:100&b:200&c:300')
  xhr.send('a=100&b=200&c=300')
  // 4. 处理服务器返回的结果
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      // 请求成功
      if (xhr.status >= 200 && xhr.status < 300) {
        div.innerHTML = xhr.response
      }
    }
  }
})

server.js配置post请求接口

javascript 复制代码
app.post('/server', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 设置响应体
  response.send('HELLO AJAX POST')
})

(2) 配置请求头

在open方法下写setRequestHeader属性,配置请求头

能否发送请求头,能否发送自定义的请求头,都需要服务器端进行设置。

这里的重点是怎么配置请求头。服务器端的设置不是重点。

server.js

javascript 复制代码
// all可接收get、post等所有形式的请求
app.all('/server', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 接收任何响应头
  response.setHeader('Access-Control-Allow-Headers', '*')
  // 设置响应体
  response.send('HELLO AJAX POST')
})

3. 响应JSON数据的两种方式

服务器:

javascript 复制代码
// all可接收get、post等所有形式的请求
app.all('/server', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  const data = { name: 'tom' }
  // 设置响应体
  response.send(JSON.stringify(data))
})

客户端:

javascript 复制代码
 // 4. 处理服务器返回的结果
 xhr.onreadystatechange = function () {
   if (xhr.readyState === 4) {
     if (xhr.status >= 200 && xhr.status < 300) {
       console.log('返回结果:', xhr.response); //返回结果: {"name":"tom"}
     }
   }
 }

服务器返回一个JSON数据,如果不处理,浏览器接收到的就是字符串。

(1) 手动,JSON.parse()


(2) 设置xhr.responseType

五、AJAX请求问题处理

1. IE浏览器缓存的问题

server.js

javascript 复制代码
app.all('/ie', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 设置响应体
  // response.send('Hello IE')
  response.send('Hello ie')
})

发送请求,获取响应结果Hello IE;更改server.js的响应体后,IE浏览器再次发送请求,获取到的响应结果还是Hello IE;因此他走的是缓存。

解决方法:

在地址URL上配置一个时间戳,这样每次发送请求时,地址都不一样,IE就会认为是新的请求,就不会走缓存了。

2. AJAX请求超时与网络异常

timeout 设置请求的时间,请求超过这个时间则会出现请求超时异常;xhr.ontimeout回调函数对请求超时进行处理。
xhr.onerror对网络异常进行处理(比如没网)

javascript 复制代码
btn.addEventListener('click', () => {
  // 1. 创建对象
  const xhr = new XMLHttpRequest();
  // 超时回调,2s
  xhr.timeout = 2000
  xhr.ontimeout = function () {
    alert('请求超时')
  }
  // 网络异常回调
  xhr.onerror = function () {
    alert('网络出问题了')
  }
  // 超时设置
  xhr.open('GET', 'http://localhost:8000/delay')
  xhr.send()
})

服务器可写一个定时器模拟请求延时

javascript 复制代码
// 网络请求超时
app.all('/delay', (request, response) => {
  // 设置响应头 设置允许跨域
  response.setHeader('Access-Control-Allow-Origin', '*')
  // 设置响应体
  setTimeout(() => {
    response.send('Hello')
  }, 5000)
})

3. 手动取消请求

取消发送请求xhr.abort()

浏览器端定义两个按钮

html 复制代码
 <button id="btn">发送请求</button>
 <button id="cancel">取消发送请求</button>

注意xhr作用域的问题:

javascript 复制代码
 // 获取元素
 const btn = document.querySelector('#btn')
 const cancel = document.querySelector('#cancel')
 let xhr = null
 // 发送GET请求
 btn.addEventListener('click', () => {
   xhr = new XMLHttpRequest();
   xhr.open('GET', 'http://localhost:8000/cancel')
   xhr.send()
   xhr.onreadystatechange = function () {
     if (xhr.readyState === 4) {
       if (xhr.status >= 200 && xhr.status < 300) {
         console.log(xhr.response);
       }
     }
   }
 })
 // 取消请求
 cancel.addEventListener('click', () => {
   xhr.abort()
 })

当请求处于发送中状态时,点击取消请求,可取消请求。

4. 请求重复发送的问题

当用户一直点击按钮,一直向服务器发送同一个请求,服务器压力会很大,影响性能。

思路就是在重新要发请求2时,判断是否已经有请求1,如果有,则取消1发送2。

javascript 复制代码
  // 获取元素
  const btn = document.querySelector('#btn')
  let xhr = null
  let isSending = false // 是否正在发送
  // 发送GET请求
  btn.addEventListener('click', () => {
    // 如果当前有发送的请求,则取消
    if (isSending) {
      xhr.abort()
    }
    // 创建对象
    xhr = new XMLHttpRequest();
    // 修改标识变量
    isSending = true
    xhr.open('GET', 'http://localhost:8000/delay')
    xhr.send()
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        // 请求结束
        isSending = false
      }
    }
  })
相关推荐
我要洋人死24 分钟前
导航栏及下拉菜单的实现
前端·css·css3
‍。。。33 分钟前
使用Rust实现http/https正向代理
http·https·rust
科技探秘人35 分钟前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人36 分钟前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR41 分钟前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香43 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍