HTTP请求:“Ajax”宗门

发布于:2025-08-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

✨宗派背景

[!Tip] 传统请求
在 Ajax(2005 年)出现之前,传统浏览器实现 HTTP 请求的方式都是同步的,且必然伴随整个页面的刷新或跳转,核心依赖于浏览器的原生 HTML 解析和请求机制。主要方式有以下几种:

1. 表单提交(<form> 标签)

这是传统浏览器处理用户输入并与服务器交互的最主要方式。
原理:通过 <form> 标签定义请求参数,用户点击提交按钮后,浏览器会将表单数据按照指定的 HTTP 方法(GET/POST)打包,发送到 action 属性指定的服务器 URL,然后加载服务器返回的全新 HTML 页面,替换当前页面。

示例代码

<!-- 传统表单提交 -->
<form action="/submit" method="POST">
  <input type="text" name="username" placeholder="用户名">
  <input type="password" name="password" placeholder="密码">
  <button type="submit">登录</button>
</form>

特点

  • 同步阻塞:提交后浏览器会 “冻结”,等待服务器响应,期间用户无法操作页面。
  • 全页面刷新:服务器返回的新 HTML 会完全替换当前页面的 DOM,导致页面闪烁。
  • 数据传输:GET 方法将数据拼在 URL 后(?username=xxx&password=xxx),POST 方法将数据放在请求体中。

2. 锚点链接(<a> 标签)

通过超链接发起 HTTP GET 请求,用于页面跳转或资源访问。
原理<a> 标签的 href 属性指定目标 URL,用户点击后,浏览器向该 URL 发送 GET 请求,服务器返回新页面(或资源),浏览器加载并替换当前页面。

示例代码

<!-- 超链接发起GET请求 -->
<a href="/user/list">查看用户列表</a>
<a href="/static/image.jpg">查看图片</a>

特点

  • 仅支持 GET 方法,数据通过 URL 参数传递(如 /user?page=1)。
  • 同步跳转:点击后立即触发页面跳转,当前页面状态(如输入框内容)会丢失。

3. 资源标签的自动请求(<img><script><link> 等)

浏览器在解析 HTML 时,会自动对带有 srchref 属性的资源标签发起 HTTP GET 请求,用于加载图片、脚本、样式表等。

示例代码

<!-- 浏览器自动发起请求加载资源 -->
<img src="/static/logo.png" alt="网站logo"> <!-- 加载图片 -->
<script src="/js/util.js"></script> <!-- 加载JavaScript -->
<link rel="stylesheet" href="/css/style.css"> <!-- 加载CSS -->

特点

  • 被动触发:由浏览器解析 HTML 时自动发起,无需用户操作。
  • 同步阻塞(部分):例如 <script> 标签加载脚本时,会阻塞后续 HTML 解析和渲染(直到脚本下载并执行完成),避免 JS 操作未解析的 DOM。
  • 仅支持 GET 方法,且无法直接获取响应数据(资源被浏览器直接用于渲染或执行)。

4. 刷新按钮或地址栏输入 URL

用户点击浏览器的 “刷新” 按钮,或在地址栏直接输入 URL 并回车,本质上是手动触发浏览器向指定 URL 发送 GET 请求,获取完整 HTML 页面并刷新。

5.传统浏览器实现ResultFul接口

在传统浏览器(Ajax 出现之前,主要依赖 HTML 原生特性)中:

  • POST 请求并非只能通过 <form> 发送,但 <form> 是最主要且标准化的方式;
  • DELETE、PUT 等 HTTP 方法无法通过原生 HTML 直接发送,因为传统浏览器的 <form> 标签仅支持 GETPOST 两种方法(method 属性只能指定这两个值)。
1. 传统浏览器中发送 POST 请求的方式

除了 <form> 标签,理论上还有一些 “非标准” 方式,但实际开发中几乎不用:

  • <iframe> 配合表单提交:通过隐藏的 <iframe> 作为表单的 target,实现 “伪异步” POST 请求(但本质仍是同步提交,只是页面不刷新),但这仍依赖 <form> 标签的 POST 能力。
  • 早期插件 / ActiveX:如 IE 中的 ActiveX 对象(如 XMLHTTP 早期版本),但这属于浏览器扩展,并非跨浏览器的原生 HTML 特性,且在 Ajax 普及前未被广泛使用。

因此,<form> 标签是传统浏览器中发送 POST 请求的标准且唯一可靠的方式

2. 传统浏览器中如何 “模拟” DELETE、PUT 请求?

由于传统浏览器不支持直接发送 DELETE、PUT 等方法,实际开发中通常通过 “POST 伪装” 实现,核心思路是:

  1. <form> 发送 POST 请求;
  2. 在请求中加入一个特殊参数(如 _method),值为 DELETEPUT
  3. 服务器端接收 POST 请求后,检查该参数,将请求 “转换” 为对应的 DELETE 或 PUT 方法处理。

示例代码(前端)

<!-- 模拟 PUT 请求 -->
<form action="/user/123" method="POST">
  <!-- 隐藏字段指定实际方法 -->
  <input type="hidden" name="_method" value="PUT">
  <input type="text" name="username" value="newName">
  <button type="submit">更新用户</button>
</form>

<!-- 模拟 DELETE 请求 -->
<form action="/user/123" method="POST">
  <input type="hidden" name="_method" value="DELETE">
  <button type="submit">删除用户</button>
</form>

服务器端处理(以 Nede.js(Express) 为例)

// 中间件解析 _method 参数,转换请求方法
app.use((req, res, next) => {
  if (req.method === 'POST' && req.body._method) {
    req.method = req.body._method.toUpperCase(); // 转换为 PUT/DELETE
    delete req.body._method;
  }
  next();
});

// 处理 PUT 请求
app.put('/user/:id', (req, res) => {
  // 实际处理更新逻辑
});

// 处理 DELETE 请求
app.delete('/user/:id', (req, res) => {
  // 实际处理删除逻辑
});

这种方式本质上仍是 POST 请求,只是通过服务器端转换实现了对其他 HTTP 方法的支持,是传统浏览器时代实现 RESTful 接口的妥协方案。

总结
  • 传统浏览器中,<form> 是发送 POST 请求的标准方式,其他方式(如插件)不具备通用性;
  • DELETE、PUT 等方法无法通过原生 HTML 直接发送,需通过 “POST + 特殊参数” 的方式模拟,由服务器端转换处理;
  • 直到 Ajax(XMLHttpRequest)出现后,浏览器才支持直接发送任意 HTTP 方法(包括 DELETE、PUT),无需依赖表单或参数转换。

传统方式的共同局限

  1. 必须刷新页面:所有请求的最终结果都是加载新的 HTML 页面,无法实现页面局部更新。
  2. 同步阻塞:请求过程中浏览器无法响应用户操作(如点击、输入),用户体验差。
  3. 数据冗余:每次请求都需要传输完整的 HTML 页面(即使只有一小部分内容变化),浪费带宽。
  4. 状态丢失:页面刷新后,当前页面的临时状态(如输入框内容、滚动位置)会被清空。

这些局限性正是 Ajax(基于 XMLHttpRequest)被提出的原因 —— 通过异步请求 + 局部 DOM 更新,解决传统同步请求的痛点,让网页交互更接近桌面应用的流畅体验。

🥸宗主Ajax

一、Ajax 的来由

[!Tip] 概念神
Ajax(Asynchronous JavaScript and XML,异步 JavaScript 和 XML)并非全新技术,而是 2005 年由 Jesse James Garrett 提出的一种技术整合方案。它将已有的技术(JavaScript、XMLHttpRequest、DOM、XML/JSON 等)结合起来,形成了一种新的网页交互模式,解决了传统网页 “每次更新都需刷新整个页面” 的问题。

二、Ajax 的作用

Ajax 的核心是异步通信,允许浏览器在不刷新整个页面的情况下,与服务器进行数据交互并局部更新页面内容。主要作用包括:

  1. 无刷新更新内容:如实时搜索建议、表单提交后即时反馈、动态加载列表等。
  2. 减少数据传输量:仅请求所需数据,而非整个页面,降低带宽消耗。
  3. 提升用户体验:避免页面闪烁和等待,交互更流畅。
  4. 异步处理:请求发送后不阻塞页面其他操作(如点击、滚动)。

三、Ajax 的优缺点

优点

  • 局部更新页面,减少用户等待时间,提升体验。
  • 减少冗余数据传输,降低服务器和网络负载。
  • 支持异步操作,不阻塞页面其他交互。
  • 可与多种后端语言(Java、Python、PHP 等)配合使用。

缺点

  • 对搜索引擎不友好(爬虫难以抓取动态加载的内容)。
  • 破坏浏览器 “前进 / 后退” 功能(需额外处理历史记录)。
  • 异步逻辑复杂,早期回调嵌套易导致 “回调地狱”(现可通过 Promise/async/await 解决)。
  • 受同源策略限制,跨域请求需额外配置(如 CORS)。

🗡️宗门圣器:XHR

[!Tip] 圣器
XMLHttpRequest(XHR),它是实现 Ajax 核心功能的关键技术。XMLHttpRequest 之所以能成为 Ajax 的核心,本质上是因为它提供了浏览器与服务器进行异步通信的能力,直接解决了传统网页 “必须刷新整个页面才能更新内容” 的痛点。

XMLHttpRequest 实现 Ajax 核心作用的关键特性

  1. 异步请求能力
    XMLHttpRequest 允许在不阻塞页面渲染和用户操作的情况下发送 HTTP 请求。

    • 传统网页的表单提交或链接跳转是 “同步” 的:请求发送后,浏览器会等待服务器响应,期间页面无法交互,直到整个页面重新加载。
    • 而 XHR 通过 open(method, url, async) 方法的第三个参数(async: true)开启异步模式,请求发送后,浏览器可以继续处理其他操作(如用户点击、滚动),直到服务器返回数据后,通过回调函数(如 onreadystatechange)处理响应。
      这种 “后台悄悄通信” 的特性,是 Ajax 实现 “无刷新更新” 的基础。
  2. 直接与服务器交换数据
    XMLHttpRequest 可以直接向服务器发送 HTTP 请求(GET、POST 等),并接收服务器返回的数据(XML、JSON、文本等),无需通过整个页面的刷新。

    • 这意味着浏览器可以只请求 “需要更新的部分数据”(而非整个 HTML 页面),大幅减少数据传输量,提升效率。
    • 例如:在搜索框输入时,通过 XHR 向服务器发送输入的关键词,服务器返回匹配的建议列表,浏览器用 JavaScript 动态更新下拉框,整个过程无需刷新页面。
  3. 支持局部页面更新
    XHR 接收数据后,结合 JavaScript 和 DOM 操作,可以只更新页面中需要变化的部分,而非整个页面。

    • 传统网页刷新会导致整个 DOM 树重新构建,页面闪烁且用户体验差。
    • 而 XHR 获取数据后,通过 document.getElementById() 等方法定位到具体 DOM 元素,用新数据修改其内容(如 innerHTML),实现 “局部刷新”。
  4. 状态监听与灵活控制
    XHR 提供了完善的状态机制,允许开发者精确控制请求的生命周期:

    • readyState 属性:表示请求的状态(0-4,4 表示请求完成)。
    • status 属性:表示 HTTP 响应状态码(如 200 表示成功,404 表示未找到)。
    • 事件回调(如 onreadystatechangeonloadonerror):可以在请求完成、成功、失败等不同阶段执行对应的逻辑(如显示加载动画、处理错误信息)。

总结

Ajax 的核心是 “异步通信 + 局部更新”,而 XMLHttpRequest 正是提供这种能力的技术载体:它让浏览器能在后台与服务器交换数据,同时不阻塞用户操作,最后通过 JavaScript 操作 DOM 实现页面局部更新。因此,XMLHttpRequest 是 Ajax 能够颠覆传统网页交互模式的核心技术基础。

🤩大师兄Axios

1. 底层依赖

[!Tip]
Axios 是一个 第三方库(需通过 npm 安装或 CDN 引入),底层在 浏览器环境 中依赖 XMLHttpRequest 对象,在 Node.js 环境 中依赖 http/https 模块,因此支持全端使用。
它本质是对原生请求能力的 高级封装,核心目标是简化网络请求的配置、处理和扩展。

2. 核心工作流程

Axios 的基本使用如下,同样基于 Promise:

// Axios 基本使用
axios({
  url: 'https://api.example.com/data',
  method: 'GET'
})
  .then(response => console.log('数据:', response.data))
  .catch(error => console.error('错误:', error));

详细原理步骤

  • 1. 合并配置:Axios 接收用户传入的配置(urlmethoddata 等),与默认配置(baseURLheaders 等)合并,生成最终请求配置。
  • 2. 执行请求拦截器:通过 axios.interceptors.request 注册的拦截器函数,可修改请求配置(如添加 token)、终止请求等。
  • 3. 发起请求
    • 浏览器环境:创建 XMLHttpRequest 对象,根据配置设置请求方法、URL、请求头,发送请求体(data)。
    • Node.js 环境:使用 http 模块创建请求,处理参数序列化和发送。
  • 4. 监听响应
    • 浏览器中通过 XMLHttpRequest.onreadystatechange 监听请求状态,当 readyState === 4 时触发响应处理。
    • 解析响应数据:自动将响应体转换为 JSON(如果响应头 Content-Typeapplication/json)。
  • 5. 执行响应拦截器:通过 axios.interceptors.response 注册的拦截器函数,可处理响应数据(如统一解密)、拦截错误(如 401 跳转登录)。
  • 6. 处理状态
    • 网络错误或 HTTP 状态码非 2xx 时,Promise 进入 reject 状态(无需手动判断)。
    • 成功时返回的 response 对象包含 data(解析后的数据)、statusheaders 等。
3. 核心特性
  • 全端支持:浏览器(XMLHttpRequest)和 Node.js(http 模块)通用。
  • 强大的拦截器:支持请求 / 响应拦截,可在请求发送前或响应处理前统一处理逻辑(如 token 管理、错误统一处理)。
  • 自动数据转换:请求时自动将 data 转换为 JSON 字符串,响应时自动解析 JSON 数据。
  • 超时控制:内置 timeout 配置,超过指定时间自动终止请求。
  • 取消请求:通过 CancelTokenAbortController 取消正在进行的请求。
  • 请求并发:提供 axios.all()axios.spread() 处理并发请求。
  • 浏览器兼容性:支持 IE8+(需引入 es6-promise polyfill 处理 Promise)。

🤩宗门天骄Fetch

一、Fetch API 原理

1. 底层依赖

Fetch 是 浏览器原生的 API(ES6+ 引入),基于 JavaScript 的 Promise 设计,直接由浏览器引擎实现(无需额外引入库)。它的底层不依赖传统的 XMLHttpRequest,而是使用了更现代的浏览器网络请求接口(可理解为浏览器内核级别的 HTTP 客户端实现)。

2. 核心工作流程

Fetch 的核心是通过 fetch() 函数发起请求,返回一个 Promise 对象,流程如下:

// Fetch 基本使用
fetch(url, options)
  .then(response => {
    // 处理响应(需手动解析响应体)
    if (!response.ok) throw new Error('请求失败');
    return response.json(); // 解析 JSON 响应
  })
  .then(data => console.log('数据:', data))
  .catch(error => console.error('错误:', error));

详细原理步骤

  • 1. 配置请求参数fetch(url, options) 接收两个参数,url 为请求地址,options 为配置对象(包含 methodheadersbodymode 等)。
  • 2. 发起请求:浏览器内核通过底层网络模块发送 HTTP 请求(支持 GET、POST、PUT、DELETE 等所有 HTTP 方法)。
  • 3. 接收响应:请求完成后,返回一个 Response 对象(包含响应状态 status、响应头 headers、响应体 body 等元数据)。
  • 4. 解析响应体Response 对象的响应体是一个 可读流(ReadableStream),需通过 json()text()blob() 等方法手动解析(这些方法返回新的 Promise,等待流解析完成)。
  • 5. 处理状态
    • 只有 网络错误(如断网)时,Promise 才会进入 reject 状态;
    • HTTP 错误状态码(如 404、500)不会触发 reject,需通过 response.okstatus 为 200-299 时为 true)手动判断。
3. 核心特性
  • 原生无依赖:浏览器内置,无需引入第三方库。
  • 基于 Promise:支持 async/await 语法,解决回调地狱。
  • 响应体流式处理:响应体以流的形式返回,适合处理大文件(如视频、大型 JSON)。
  • 跨域控制:通过 options.mode 配置跨域策略(corsno-corssame-origin)。
  • 局限性
    • 无默认超时设置(需手动通过 AbortController 实现)。
    • 无请求 / 响应拦截器(需手动封装)。
    • 不支持自动转换 JSON 数据(需显式调用 response.json())。
    • 浏览器兼容性:IE 完全不支持,需通过 polyfill 兼容旧浏览器。

🎆比武大会

对比维度 axios fetch
底层依赖 浏览器端基于 XMLHttpRequest,Node 端基于 http 模块 浏览器原生 API,基于更现代的网络接口(非 XHR)
API 设计 函数式 API,支持 axios(config) 或快捷方法(axios.get() 全局 fetch(url, options) 函数,返回 Promise
返回值 包装后的响应对象({ data, status, headers, ... } 原生 Response 对象(需手动解析响应体)
数据转换 自动转换:
- 请求时自动将 data 转为 JSON
- 响应时自动解析 JSON
需手动解析:
- 响应体通过 response.json()/text() 等方法解析(返回新 Promise)
错误处理 主动捕获错误:
- 网络错误触发 reject
- HTTP 非 2xx 状态码(如 404)触发 reject
被动捕获错误:
- 仅网络错误触发 reject
- HTTP 错误状态码(如 404)不触发 reject,需通过 response.ok 判断
拦截器 内置请求 / 响应拦截器(axios.interceptors),可全局处理请求(如添加 token) 无内置拦截器,需手动封装(如通过高阶函数)
超时控制 内置 timeout 配置(如 { timeout: 3000 } 无内置超时,需通过 AbortController + Promise.race 实现
取消请求 支持两种方式:
- 旧版 CancelToken(已废弃)
- 新版 AbortController(推荐)
仅支持 AbortController(与 Web 标准一致)
请求体格式 自动处理不同格式:
- JSON 自动设置 Content-Type: application/json
- FormData 自动设置 multipart/form-data
需手动设置 Content-Type
- 如 JSON 需显式设置 headers: { 'Content-Type': 'application/json' }
并发请求 提供 axios.all()axios.spread() 处理并发 需通过 Promise.all() 手动处理
浏览器兼容性 支持 IE8+(需 es6-promise 兼容 Promise) 不支持 IE,现代浏览器(Chrome 42+、Firefox 39+)支持
额外功能 支持 JSONP、请求重试、防御 XSRF 等 无额外功能,仅提供基础请求能力

网站公告

今日签到

点亮在社区的每一天
去签到