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
      }
    }
  })
相关推荐
G_G#4 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界19 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路28 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug32 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213834 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全