【AJAX-Day1】HTTP协议与XHR基础

3 阅读5分钟

【AJAX-Day1】HTTP协议与XHR基础

🎯 核心目标:理解 AJAX 是什么、HTTP 请求/响应结构、使用原生 XHR 发送请求、掌握 Axios 基本用法


一、AJAX 概述

1.1 什么是 AJAX?

AJAX(Asynchronous JavaScript And XML)是一种无需刷新页面就能与服务器交换数据并更新部分页面的技术。

传统网页交互:
用户操作 → 整页提交 → 服务器响应 → 整页刷新(体验差)

AJAX 交互:
用户操作 → 后台异步请求 → 服务器响应 → 局部更新页面(体验好)

AJAX 能做什么:

  • 搜索框实时联想(百度、淘宝)
  • 下拉刷新 / 上拉加载更多
  • 表单提交不刷新页面
  • 实时聊天消息
  • 地图数据动态加载

1.2 客户端与服务端

客户端(Client)      ←→       服务端(Server)
浏览器、App           发请求     Node.js、Java、PHP、Python...
                      收响应     提供数据、处理业务逻辑

URL 格式:

https://www.example.com:8080/api/users?page=1&size=10#section
  ↑        ↑             ↑     ↑              ↑          ↑
协议     域名/IP         端口   路径          查询参数     锚点

二、HTTP 协议

2.1 什么是 HTTP?

HTTP(HyperText Transfer Protocol)是客户端和服务端之间数据传输的规则,规定了请求和响应的格式。

2.2 HTTP 请求报文

请求行:   GET /api/users?page=1 HTTP/1.1
请求头:   Host: api.example.com
          Content-Type: application/json
          Authorization: Bearer eyJhbG...
          Accept: application/json
空行:    (必须有,分隔请求头和请求体)
请求体:   {"name":"张三","age":18}   ← GET 请求没有请求体

请求方法(HTTP Verbs):

方法语义有请求体常见用途
GET获取资源查询列表、详情
POST新建资源提交表单、上传
PUT完整更新更新整个资源
PATCH部分更新修改某个字段
DELETE删除资源删除操作

2.3 HTTP 响应报文

状态行:   HTTP/1.1 200 OK
响应头:   Content-Type: application/json; charset=utf-8
          Content-Length: 256
          Date: Mon, 06 Apr 2026 12:00:00 GMT
空行:
响应体:   {"code":200,"data":[...],"message":"success"}

常见状态码:

状态码含义说明
200OK请求成功
201Created资源创建成功
301Moved Permanently永久重定向
302Found临时重定向
304Not Modified缓存未过期,用本地缓存
400Bad Request请求参数有误
401Unauthorized未登录/Token失效
403Forbidden无权限
404Not Found资源不存在
405Method Not Allowed请求方法不允许
500Internal Server Error服务器内部错误
502Bad Gateway网关错误(通常是服务挂了)

2.4 请求头常见字段

Content-Type: application/json            请求体是 JSON
Content-Type: application/x-www-form-urlencoded  表单数据(key=val&key=val)
Content-Type: multipart/form-data         文件上传
Authorization: Bearer <token>             携带身份令牌
Accept: application/json                  告诉服务器我能接受的格式
Accept-Language: zh-CN,zh;q=0.9          语言偏好
Cache-Control: no-cache                   不使用缓存

三、原生 XMLHttpRequest(XHR)

3.1 基本使用

// 1. 创建 XHR 对象
const xhr = new XMLHttpRequest()

// 2. 配置请求(方法、URL、是否异步)
xhr.open('GET', 'https://api.example.com/users')

// 3. 监听状态变化
xhr.addEventListener('loadend', () => {
  // xhr.status:HTTP 状态码
  // xhr.response:响应体(字符串)
  if (xhr.status === 200) {
    const data = JSON.parse(xhr.response)
    console.log(data)
  } else {
    console.error('请求失败:', xhr.status)
  }
})

// 4. 发送请求
xhr.send()

3.2 readyState 状态值

0 - UNSENT:XHR 对象已创建,但未调用 open()
1 - OPENED:open() 已调用
2 - HEADERS_RECEIVED:send() 已调用,响应头已收到
3 - LOADING:响应体正在接收中
4 - DONE:响应完整接收完毕
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText))
  }
}

💡 推荐用 loadend 事件替代 readystatechange,更简洁。

3.3 GET 请求 —— 携带查询参数

// 参数拼接在 URL 后面
const params = new URLSearchParams({
  page: 1,
  size: 10,
  keyword: '张三'
})
const url = `https://api.example.com/users?${params}`
// → https://api.example.com/users?page=1&size=10&keyword=%E5%BC%A0%E4%B8%89

xhr.open('GET', url)
xhr.send()  // GET 请求 send() 不传参数

3.4 POST 请求 —— 携带请求体

const xhr = new XMLHttpRequest()
xhr.open('POST', 'https://api.example.com/users')

// 必须设置 Content-Type!
xhr.setRequestHeader('Content-Type', 'application/json')

xhr.addEventListener('loadend', () => {
  if (xhr.status === 201) {
    console.log('创建成功:', JSON.parse(xhr.response))
  }
})

// send() 中传递请求体(必须序列化为字符串)
xhr.send(JSON.stringify({
  name: '张三',
  age: 18,
  email: 'zhangsan@example.com'
}))

3.5 XHR 封装(Promise 化)

function request(method, url, data = null) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    xhr.setRequestHeader('Content-Type', 'application/json')
    
    xhr.addEventListener('loadend', () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.response))
      } else {
        reject(new Error(`HTTP Error: ${xhr.status}`))
      }
    })
    
    xhr.addEventListener('error', () => {
      reject(new Error('Network Error'))
    })
    
    xhr.send(data ? JSON.stringify(data) : null)
  })
}

// 使用
request('GET', '/api/users')
  .then(data => console.log(data))
  .catch(err => console.error(err))

四、Axios 基础

4.1 为什么用 Axios?

原生 XHR 代码繁琐,Axios 是基于 XHR 的封装库,提供更简洁的 API:

  • 自动 JSON 序列化/反序列化
  • Promise-based API
  • 拦截器机制
  • 请求取消
  • 请求/响应转换

4.2 引入 Axios

<!-- CDN 引入(学习时用) -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

<!-- npm 安装(项目中用) -->
<!-- npm install axios -->
<!-- import axios from 'axios' -->

4.3 基本使用

// GET 请求
axios({
  method: 'GET',
  url: 'https://api.example.com/users',
  params: { page: 1, size: 10 }  // 查询参数(自动拼到URL)
}).then(result => {
  // result.data:响应体数据(axios 已自动 JSON 解析)
  // result.status:HTTP 状态码
  // result.headers:响应头
  console.log(result.data)
})

// POST 请求
axios({
  method: 'POST',
  url: 'https://api.example.com/users',
  data: { name: '张三', age: 18 }  // 请求体(自动 JSON 序列化)
}).then(result => {
  console.log(result.data)
})

4.4 快捷方法

// GET
axios.get('/api/users', { params: { page: 1 } })

// POST
axios.post('/api/users', { name: '张三', age: 18 })

// PUT
axios.put('/api/users/1', { name: '李四' })

// DELETE
axios.delete('/api/users/1')

// PATCH
axios.patch('/api/users/1', { age: 20 })

4.5 async/await 写法(推荐)

async function getUsers() {
  try {
    const { data } = await axios.get('/api/users', {
      params: { page: 1, size: 10 }
    })
    console.log(data)
    return data
  } catch (error) {
    if (error.response) {
      // 服务器响应了,但状态码不在 2xx 范围
      console.error('状态码:', error.response.status)
      console.error('错误信息:', error.response.data)
    } else if (error.request) {
      // 请求发出去了,但没有收到响应(网络问题)
      console.error('网络错误')
    } else {
      console.error('请求配置错误:', error.message)
    }
  }
}

五、综合练习

练习:图书管理系统(增删改查)

const BASE_URL = 'http://ajax-base-api-t.itheima.net'

// 获取图书列表
async function getBooks() {
  const { data } = await axios.get(`${BASE_URL}/api/books`)
  return data.data
}

// 新增图书
async function addBook(bookName) {
  const { data } = await axios.post(`${BASE_URL}/api/books`, {
    bookname: bookName
  })
  return data
}

// 删除图书
async function deleteBook(id) {
  const { data } = await axios.delete(`${BASE_URL}/api/books/${id}`)
  return data
}

// 更新图书
async function updateBook(id, bookName) {
  const { data } = await axios.put(`${BASE_URL}/api/books/${id}`, {
    bookname: bookName
  })
  return data
}

六、知识图谱

HTTP协议与XHR基础
├── AJAX
│   ├── 定义:异步JSXML,局部刷新页面
│   └── 场景:搜索联想、分页加载、表单提交
├── HTTP 协议
│   ├── 请求报文:请求行/头/体(方法 + URL + 参数)
│   ├── 响应报文:状态行/头/体(状态码 + 数据)
│   ├── 请求方法:GET/POST/PUT/PATCH/DELETE
│   └── 状态码:200/201/301/304/400/401/403/404/500
├── XHRXMLHttpRequest)
│   ├── open() → send() → loadend 事件
│   ├── GET:参数拼 URLURLSearchParams)
│   ├── POST:setRequestHeader + send(JSON)
│   └── Promise 封装
└── Axios
    ├── 引入:CDN / npm
    ├── 配置对象:method/url/params/data
    ├── 快捷方法:get/post/put/delete/patch
    └── async/await + try/catch(推荐)

七、高频面试题

Q1:GET 和 POST 的区别?

① GET 参数在 URL(有长度限制),POST 在请求体(无限制);② GET 是幂等的(多次请求结果相同),POST 不是;③ GET 有缓存,POST 不缓存;④ GET 用于获取数据,POST 用于提交/创建数据。

Q2:HTTP 状态码 301 和 302 的区别?

都是重定向,但 301 是永久重定向(浏览器/搜索引擎会记住新地址),302 是临时重定向(每次仍发到原地址)。SEO 场景中 301 更常用。

Q3:AJAX 请求为什么是异步的?

因为网络请求耗时不确定,如果同步等待会阻塞 JS 线程(UI 卡死)。通过事件循环机制,AJAX 请求被放到 Web APIs 中执行,完成后回调函数进入宏任务队列,不影响主线程。


➡️ 下一篇Day2 - Promise与回调地狱