当前位置: 首页 > news >正文

Ajax 详解

Ajax 详解

前言

想象一下,你正刷着微博,手指轻轻一滑,新的动态便自动加载出来,页面没有闪白、没有跳转,仿佛内容本就静静躺在那里等你发现。又或者,你在淘宝搜索框输入“卫衣”,还没按下回车,相关推荐已经悄然浮现——这一切,都离不开一个改变了网页交互方式的技术:Ajax

在 Ajax 出现之前,网页就像一本只能翻页的书:想看下一页?必须整页翻过去。哪怕只是改一个字,浏览器也得重新加载整个页面,用户体验如同在石器时代拨号上网。直到 2005 年,Ajax 被正式命名并广泛推广,网页才真正“活”了过来。

Ajax 并不是一门新语言,也不是某种神秘的黑科技,它更像是一位“幕后协调员”,让 JavaScript 能在不打扰用户的情况下,悄悄与服务器对话,只拿需要的数据,只更新需要的部分。从此,网页从“静态文档”进化为“动态应用”。

一、Ajax 概述

1.1 什么是 Ajax?

Ajax,全称 Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),是一种用于创建快速、动态、交互式网页应用的技术组合。它并不是一门新的编程语言,也不是一个独立的框架,而是一种利用现有 Web 技术协同工作的编程范式

其核心思想是:在不重新加载整个页面的前提下,与服务器进行异步通信,并局部更新网页内容

这意味着,用户在浏览网页时,可以无需等待页面刷新,就能获取新数据、提交表单、加载更多内容,从而获得接近原生应用的流畅体验。

1.2 传统网页 vs Ajax 网页

对比项传统网页交互使用 Ajax 的网页交互
页面刷新每次操作都需重新加载整个页面仅局部更新,无需整页刷新
用户体验中断感强,等待时间长流畅自然,响应迅速
数据传输传输整个 HTML 页面仅传输必要数据(如 JSON、XML)
服务器压力较高,频繁生成完整页面较低,只处理数据请求
技术实现表单提交 + 页面跳转JavaScript 发起异步请求 + DOM 更新

举个例子:
在一个传统的博客网站中,用户提交评论后,页面会跳转或刷新,重新加载整个文章页。
而使用 Ajax 后,评论数据通过后台悄悄发送,提交成功后,新评论直接“冒”在评论区下方,用户甚至不需要离开当前阅读位置。

1.3 Ajax 的核心技术组成

Ajax 并非单一技术,而是多种 Web 技术协同工作的结果:

  1. HTML/XHTML:用于构建页面结构;
  2. CSS:用于控制页面样式与布局;
  3. JavaScript:核心驱动语言,负责发起请求、处理响应;
  4. DOM(Document Object Model):JavaScript 通过操作 DOM 实现局部内容更新;
  5. XmlHttpRequest 或 Fetch API:与服务器进行异步通信的关键对象;
  6. XML / JSON:早期常用 XML 传输数据,如今 JSON 已成为主流数据格式。

虽然 Ajax 名字中包含 XML,但现代开发中,JSON(JavaScript Object Notation)因其轻量、易解析的特性,已成为 Ajax 数据交换的首选格式。

1.4 Ajax 的优势

  • 提升用户体验:无刷新更新,操作更流畅;
  • 减少服务器负载:只请求数据,而非整个页面;
  • 降低带宽消耗:传输数据量小,节省流量;
  • 支持异步操作:用户可继续操作页面,无需等待响应;
  • 前后端分离友好:便于构建 RESTful API 和单页应用(SPA)。

1.5 Ajax 的局限与注意事项

  • 依赖 JavaScript:用户需启用 JS,否则功能失效;
  • 对 SEO 不够友好:早期搜索引擎难以抓取动态内容(现已有改善方案);
  • 调试相对复杂:异步逻辑可能增加调试难度;
  • 跨域限制:受同源策略约束,需通过 CORS 或代理解决;
  • 历史管理问题:早期 SPA 需手动管理浏览器历史记录(现可通过 History API 解决)。

二、Ajax原理

2.1 Ajax 入门案例

在学习原理之前,先写一个入门案例,走一个流程,方便后面的理解。

我使用的是Java,那我的服务端写一个HelloServlet。

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("hello ajax");}
}

写一个html界面,方便展示。

界面中写了一个button,用来进行事件绑定,写一个span,用来展示发送Ajax请求后,服务端返回的信息。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello Ajax</title><script>function getMessage() {//实例化一个XmlHttpRequestvar XmlHttpRequest = new XmlHttpRequest();//设置XmlHttpRequest对象的回调函数XmlHttpRequest.onreadystatechange = function () {if (XmlHttpRequest.readyState === 4 && XmlHttpRequest.status === 200) {var p = document.getElementById("message");p.innerHTML = XmlHttpRequest.responseText;p.style.color = "red";}};//设置发送请求的方式和请求的资源路径XmlHttpRequest.open("GET","/JavaWeb_07/hello");//发送请求XmlHttpRequest.send();}</script>
</head>
<body>
<button onclick="getMessage()">按钮</button>
<span id="message"></span>
</body>
</html>

可以看到,我们button按钮绑定了getMessage()方法。

在getMessage()中,

1.实例化一个XmlHttpRequest对象

var XmlHttpRequest = new XmlHttpRequest();

2.设置XmlHttpRequest对象的回调函数

XmlHttpRequest.onreadystatechange = function () {if (XmlHttpRequest.readyState === 4 && XmlHttpRequest.status === 200) {var p = document.getElementById("message");p.innerHTML = XmlHttpRequest.responseText;p.style.color = "red";}};

3.设置发送请求的方式和请求的资源路径

XmlHttpRequest.open("GET","/JavaWeb_07/hello");

4.发送请求

XmlHttpRequest.send();

接下来我们启动服务,点击按钮进行测试。

可以发现页面不用刷新,便可以展示我们服务端返回的信息,hello ajax

在这里插入图片描述

可以看到我们请求的Type是xhr,这恰恰证明了我们刚刚使用了Ajax。

在这里插入图片描述

2.2 Ajax 原理

  1. 事件触发(如点击按钮或页面加载)。
  2. AJAX 请求:通过 JavaScript 创建一个 XmlHttpRequest 对象,向服务器发送请求。
  3. 服务器处理请求:服务器(通常使用 PHP、Node.js 等)接收请求,处理并返回响应数据(JSON、XML、HTML等)。
  4. AJAX 响应处理:浏览器接收响应,使用 JavaScript 在页面上更新内容,而无需重新加载整个页面。

在这里插入图片描述

2.3 XmlHttpRequest

XmlHttpRequest 是 AJAX 的基础。

2.3.1 创建 XmlHttpRequest 对象

所有现代浏览器(IE7+、Edge、Firefox、Chrome、Safari 以及 Opera)均内建 XmlHttpRequest 对象。

创建 XmlHttpRequest 对象的语法:

var xhr = new XmlHttpRequest();
2.3.2 XmlHttpRequest 请求

XmlHttpRequest 对象用于和服务器交换数据。

通过该对象,我们可以在不刷新页面的情况下,向服务器发送请求并接收响应数据,从而实现网页的局部更新。

要发起一个 HTTP 请求,主要使用 XmlHttpRequest 的两个关键方法:open()send()

基本语法

xhr.open(method, url, async);
xhr.send(string);
  • open():设置请求的基本参数。
  • send():实际发送请求到服务器。
1、open(method, url, async)

该方法用于配置请求的类型、目标地址以及是否异步执行。

参数说明
method请求方法,通常为 "GET""POST"
url服务器上资源的路径(可以是 .txt.json.php.asp 等)
async布尔值,true 表示异步,false 表示同步(推荐使用 true

示例:

xhr.open("GET", "/JavaWeb_07/hello", true);
2、send(string)

该方法用于发送请求。参数仅在使用 POST 请求时需要传入要提交的数据。

参数说明
string要发送的数据字符串(仅用于 POST 请求)

示例:

xhr.send(); // GET 请求无需数据xhr.send("name=Tom&age=25"); // POST 请求发送表单数据
3、GET VS POST
对比项GETPOST
用途获取数据提交数据
缓存可能被缓存(需注意)不缓存,适合更新操作
数据长度有 URL 长度限制无限制,适合大数据
安全性数据暴露在 URL 中相对更安全(仍需 HTTPS)
编码要求特殊字符可能出错更稳定,支持复杂数据

建议使用 POST 的场景:

  • 提交表单数据(如注册、登录)
  • 更新服务器数据(如修改数据库)
  • 发送大量或包含敏感信息的数据
4、GET 请求示例
xhr.open("GET", "/JavaWeb_07/hello", true);
xhr.send();

注意:浏览器可能会缓存 GET 请求的结果。为避免缓存,可在 URL 后添加唯一参数(如时间戳或随机数):

xhr.open("GET", "/JavaWeb_07/hello?t=" + Math.random(), true);
xhr.send();

若需传递参数,直接拼接在 URL 中:

xhr.open("GET", "/JavaWeb_07/hello?keyword=ajax&limit=10", true);
xhr.send();

5、POST 请求示例

发送 POST 请求时,建议设置正确的请求头(Content-Type),以模拟表单提交行为:

xhr.open("POST", "/JavaWeb_07/hello", true);// 设置 HTTP 请求头,表示发送的是表单格式数据
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");// 发送键值对形式的数据
xhr.send("fname=Henry&lname=Ford");
6、setRequestHeader(header, value)

用于设置 HTTP 请求头,常用于 POST 请求。

参数说明
header头字段名称,如 "Content-Type"
value头字段值,如 "application/x-www-form-urlencoded"

注意:setRequestHeader() 必须在 open() 之后、send() 之前调用。


7、异步处理:async = true(推荐)

Ajax 的核心优势在于“异步”。将 async 设为 true,JavaScript 不会阻塞等待服务器响应,用户仍可操作页面。

在这里插入图片描述

此时,必须通过监听 onreadystatechange 事件来处理响应:

xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {document.getElementById("myDiv").innerHTML = xhr.responseText;}
};
xhr.open("GET", "/JavaWeb_07/hello", true);
xhr.send();

我们将在下一节详细讲解 onreadystatechange 事件与 readyState 状态码。


8、同步请求:async = false(不推荐)

虽然可以设置 async = false 实现同步请求,但这会导致 JavaScript 阻塞,直到服务器返回响应,期间页面将无法响应用户操作。

在这里插入图片描述

xhr.open("GET", "ajax_info.txt", false);
xhr.send();
// JavaScript 会在这里暂停,直到响应完成
document.getElementById("myDiv").innerHTML = xhr.responseText;

警告:同步请求会导致页面“冻结”,影响用户体验,现代开发中应避免使用

2.3.3 XmlHttpRequest 响应

当服务器接收到客户端请求后,会返回相应的数据。要获取并处理这些响应数据,我们可以通过 XmlHttpRequest 对象提供的两个核心属性:responseTextresponseXML

根据服务器返回的数据格式,选择合适的属性来接收和解析响应内容,是实现动态页面更新的关键步骤。

属性描述
responseText以字符串形式返回服务器响应数据(适用于文本、HTML、JSON 等非 XML 数据)
responseXML以 XML DOM 对象形式返回服务器响应数据(仅当响应为 XML 格式时有效)

使用建议:

  • 大多数现代应用使用 JSON 格式传输数据 → 推荐使用 responseText 并配合 JSON.parse() 解析。
  • 若后端返回 XML 数据(较少见),可使用 responseXML 进行 DOM 操作。

1、responseText:获取字符串响应

responseText 是最常用的响应属性,它将服务器返回的内容作为纯字符串返回,无论内容是 HTML 片段、JSON 文本还是普通文本。

使用场景

  • 加载静态文本文件(如 .txt
  • 接收 JSON 格式数据(需手动解析)
  • 动态插入 HTML 内容到页面

示例:处理 JSON 响应

如果服务器返回的是 JSON 字符串(如 { "name": "Tom", "age": 25 }),需使用 JSON.parse() 转换为 JavaScript 对象:

{ "name": "Tom", "age": 25 }
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello Ajax</title><script>function getMessage() {//实例化一个XMLHttpRequestvar xhr = new XMLHttpRequest();//设置xmlHttpRequest对象的回调函数//xmlHttpRequest.readyState   1 2 3 4//xmlHttpRequest.status   响应状态码,相应行状态码 200 404 500 304xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {var data = JSON.parse(xhr.responseText);document.getElementById("message").innerText = data.name + " " + data.age;}};xhr.open("GET", "/static/user.json", true);xhr.send();}</script>
</head>
<body>
<button onclick="getMessage()">按钮</button><br>
<span id="message"></span>
</body>
</html>

在这里插入图片描述


2、responseXML:解析 XML 响应

如果服务器返回的是 XML 格式的数据,responseXML 属性会自动将其解析为一个可用的 XML DOM 对象,你可以像操作 HTML DOM 一样遍历和提取其中的数据。

注意:只有当服务器正确设置响应头 Content-Type: application/xmltext/xml,且返回内容为合法 XML 时,responseXML 才有效。

示例:读取并解析 XML 文件

假设服务器返回一个名为 cd_catalog.xml 的文件,内容如下:

<CATALOG><CD><TITLE>Empire Burlesque</TITLE><ARTIST>Bob Dylan</ARTIST><COUNTRY>USA</COUNTRY></CD><CD><TITLE>Hide Your Heart</TITLE><ARTIST>Bonnie Tyler</ARTIST><COUNTRY>UK</COUNTRY></CD>
</CATALOG>

我们可以使用 responseXML 获取该 XML 对象,并提取所有艺术家名称:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Hello Ajax</title><script>function getMessage() {//实例化一个XMLHttpRequestvar xhr = new XMLHttpRequest();//设置xmlHttpRequest对象的回调函数xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {// 获取 XML DOM 对象var xmlDoc = xhr.responseXML;var txt = "";var artists = xmlDoc.getElementsByTagName("ARTIST");// 遍历所有 ARTIST 元素for (var i = 0; i < artists.length; i++) {txt += artists[i].childNodes[0].nodeValue + "<br>";}// 显示结果document.getElementById("message").innerHTML = txt;}};xhr.open("GET", "/static/cd_catalog.xml", true);xhr.send();}</script>
</head>
<body>
<button onclick="getMessage()">按钮</button><br>
<span id="message"></span>
</body>
</html>

在这里插入图片描述

如何选择响应类型?

响应类型推荐属性处理方式
纯文本 / HTML 片段responseText直接插入 innerHTML
JSON 数据responseText使用 JSON.parse() 转换
XML 数据responseXML使用 getElementsByTagNamegetAttribute 等 DOM 方法解析
  1. 优先使用 JSON
    尽管 Ajax 名字中有 XML,但如今 JSON 已成为主流数据格式,更轻量、更易解析。
  2. 确保编码一致
    服务器应正确设置字符编码(如 UTF-8),避免中文乱码。
  3. 检查响应状态
    始终在 readyState === 4status === 200 时才处理响应,防止错误数据被使用。
  4. XML 使用场景有限
    XML 多用于遗留系统或特定行业标准(如 SOAP 接口),新项目建议使用 JSON。
2.3.4 XMLHttpRequest onreadystatechange 事件

在使用 XMLHttpRequest 发起异步请求后,我们无法预知服务器何时返回响应。为了在响应就绪时及时处理数据,必须依赖一个关键机制:onreadystatechange 事件

这个事件是 Ajax 实现“异步通信”的核心,它允许我们在请求状态变化时执行特定逻辑,确保只在数据准备就绪时进行操作。


1、onreadystatechange

onreadystatechange 是一个事件处理函数,每当 XMLHttpRequest 对象的 readyState 属性发生变化时(从 0 到 4),该事件就会被触发一次。

我们可以将处理响应的逻辑写在这个事件的回调函数中,从而实现对请求生命周期的精确控制。

基本语法:

xhr.onreadystatechange = function() {// 当 readyState 改变时执行的代码
};

注意:必须在调用 send() 之前绑定 onreadystatechange,否则可能错过某些状态。


2、readyState:请求的五种状态

readyState 属性表示当前请求的生命周期状态,它是一个从 04 的整数,共五个阶段:

状态说明
0UNSENT请求未初始化,尚未调用 open() 方法
1OPENED已调用 open(),服务器连接已建立
2HEADERS_RECEIVED已接收到响应头(send() 已调用)
3LOADING正在接收响应体(数据下载中)
4DONE请求完成,响应已就绪,可安全处理数据

只有当 readyState === 4 时,表示整个请求过程结束,才能安全地读取 responseTextresponseXML


3、status:HTTP 响应状态码

即使请求完成(readyState === 4),也不代表成功获取数据。我们还需要检查 status 属性来判断响应是否成功。

常见状态码:

状态码含义
200OK —— 请求成功,服务器正常返回数据 ✅
404Not Found —— 请求的资源不存在 ❌
500Internal Server Error —— 服务器内部错误 ❌
403Forbidden —— 无权限访问 ❌
400Bad Request —— 请求语法错误 ❌

标准用法:判断请求是否成功完成

最经典的写法是同时检查 readyStatestatus

xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {// 请求完成且成功,处理响应document.getElementById("myDiv").innerHTML = xhr.responseText;}
};

✅ 只有当两个条件都满足时,才说明:

  • 请求已完成(readyState === 4
  • 服务器返回了有效数据(status === 200

4、事件触发次数

onreadystatechange 事件在整个请求过程中会被触发 4 次以上(理论上最多 5 次,对应 0→1→2→3→4 的每次变化),例如:

xhr.onreadystatechange = function() {console.log("当前 readyState:", xhr.readyState);
};

在这里插入图片描述

实际开发中,我们通常只关心 readyState === 4 的情况,其他状态可用于调试或实现加载进度提示。


5、使用回调函数实现可复用的 Ajax 请求

如果你的页面中有多个 Ajax 请求,为了避免重复代码,可以封装一个通用函数,并通过回调函数(callback)传递不同的处理逻辑。

示例:封装通用 Ajax 函数

function loadXMLDoc(url, callback) {var xhr = new XMLHttpRequest();xhr.onreadystatechange = function() {if (xhr.readyState === 4 && xhr.status === 200) {// 请求成功,执行传入的回调函数callback(xhr.responseText);} else if (xhr.readyState === 4 && xhr.status !== 200) {// 请求完成但出错console.error("请求失败,状态码:", xhr.status);}};xhr.open("GET", url, true);xhr.send();
}

调用示例:

loadXMLDoc("/static/user.json", function(data) {var user = JSON.parse(data);document.getElementById("message").innerHTML = user.name;
});

💡 这种“函数传参 + 回调”的方式,是早期 JavaScript 实现异步编程的经典模式,为后续 Promise 和 async/await 奠定了基础。

三、使用Ajax

Ajax 的核心在于无需刷新页面即可与服务器通信。实现这一能力的关键是 XMLHttpRequest 对象。

1、原生Ajax

所谓“原生 Ajax”,是指不依赖 jQuery、Axios 等第三方库,直接使用浏览器提供的 XMLHttpRequest API 发起异步请求。这是理解 Ajax 原理的基础,也是现代前端开发的必备知识

使用原生 JavaScript 发送一个完整的 Ajax 请求,并结合后端 Servlet 实现数据交互。

1.1 GET 请求

GET 请求是最常见的 Ajax 请求方式,通常用于获取数据。参数通过 URL 查询字符串(?key=value)传递。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-GET</title>
</head>
<body><div><button id="btn">点击 hello ajax</button><span id="result"></span></div><script>var btn = document.getElementById("btn");var result = document.getElementById("result");btn.onclick = function () {var xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {result.innerHTML = xhr.responseText;result.style.color = "green";}};// GET 请求:参数通过 URL 传递xhr.open("GET", "/JavaWeb_07/get?username=zhangsan");xhr.send(); // GET 请求 send() 参数为 null 或省略};</script>
</body>
</html>
@WebServlet("/get")
public class GetServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//接收参数String username = req.getParameter("username");System.out.println("用户名:" + username);//做出响应resp.getWriter().write("username = " + username);}
}
  • xhr.open("GET", url):URL 中携带查询参数。
  • xhr.send():GET 请求不需发送请求体,传 null 或不传参数。
  • 适用于获取数据,如加载新闻、用户信息等。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-GET.html,点击按钮

在这里插入图片描述
在这里插入图片描述

可以看到我们的请求路径中携带参数。


1.2 POST 请求

POST 请求用于向服务器提交数据,数据包含在请求体中,安全性高于 GET,且无长度限制。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-POST</title>
</head>
<body><form id="form">用户名:<input type="text" name="username" id="username"/> <br>密码:<input type="password" name="password" id="password"/> <br><input type="submit" id="btn"/></form><div id="result" style="border: red 1px solid; width: 100px; height: 100px"></div><script>var btn = document.getElementById('btn');btn.addEventListener('click', function (e) {e.preventDefault(); // 阻止表单默认提交var username = document.getElementById('username').value;var password = document.getElementById('password').value;var result = document.getElementById('result');var xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {result.innerHTML = xhr.responseText;result.style.color = 'green';}};xhr.open('POST', '/JavaWeb_07/post');// 必须设置请求头,告知服务器数据格式为表单xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');xhr.send('username=' + username + '&password=' + password);});</script>
</body>
</html>
@WebServlet("/post")
public class PostServlet extends HttpServlet{@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取参数req.setCharacterEncoding("utf-8");String username = req.getParameter("username");String password = req.getParameter("password");//处理....System.out.println("用户名:" + username);System.out.println("密码:" + password);//响应resp.setContentType("text/html;charset=utf-8");resp.getWriter().write("username = " + username + " password = " + password);}
}
  • setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'):必须设置,否则服务器无法解析表单数据。
  • send(data):POST 请求的数据通过 send() 发送。
  • 适用于登录、注册、提交表单等场景。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-POST.html,在表单中输入用户名和密码 admin 111111,点击按钮。

在这里插入图片描述
在这里插入图片描述

可以看到请求体中携带着表单数据。


1.3 响应 JSON

现代 Web 开发中,JSON 是主流的数据交换格式。

前端可通过 JSON.parse() 手动解析,

或使用 xhr.responseType = 'json' 自动解析。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-响应JSON</title>
</head>
<body><button id="btn">获取 JSON 数据</button> <br><div id="result" style="border: red 1px solid; width: 200px; height: 500px;"></div><script>var btn = document.getElementById('btn');btn.addEventListener('click', function () {var result = document.getElementById('result');var xhr = new XMLHttpRequest();// 设置响应类型为 JSON,自动解析xhr.responseType = 'json';xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {//处理响应数据--json// result.innerHTML = xhr.responseText;//方式一:手动设置// var data = JSON.parse(xhr.responseText);// var html = '';// for (var key in data) {//     console.log(key + ':' + data[key]);//     html += key + ':' + data[key] + '<br>';// }// result.innerHTML = html;//方式二:设置响应体的数据类型var html ='';var data = xhr.response;for (var key in data) {console.log(key + ':' + data[key]);html += key + ':' + data[key] + '<br>';}result.innerHTML = html;}};xhr.open('GET', '/JavaWeb_07/json');xhr.send();});</script>
</body>
</html>
@WebServlet("/json")
public class JSONServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 设置响应格式为 JSON,编码 UTF-8resp.setContentType("application/json;charset=UTF-8");// 构造 JSON 字符串(注意:字符串中的双引号要转义)String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 获取输出流并写入响应resp.getWriter().write(json);}
}
  • resp.setContentType("application/json"):必须设置,否则浏览器可能不识别为 JSON。
  • xhr.responseType = 'json':自动将响应体解析为 JavaScript 对象。
  • 也可使用 JSON.parse(xhr.responseText) 手动解析。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-JSON.html,点击按钮。

在这里插入图片描述
在这里插入图片描述

可以看到服务端相应的是json类型的字符串,我们通过xhr.responseType = 'json':自动将响应体解析为 JavaScript 对象。


1.4 IE 缓存问题

IE 浏览器会对 Ajax 请求进行缓存,导致相同 URL 的请求不会重新发送,数据无法及时更新。

xhr.open('GET', '/JavaWeb_07/json?t=' + new Date().getTime());

其他方法:设置请求头 Cache-Control: no-cache,但添加时间戳最简单有效。


1.5 请求超时与网络问题

网络不稳定时,请求可能长时间无响应。应设置超时机制错误处理,提升用户体验。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-超时与网络问题</title>
</head>
<body><button id="btn">发送请求</button><span id="result"></span>
</body>
<script>var btn = document.getElementById("btn");var result = document.getElementById("result");btn.onclick = function () {var xhr = new XMLHttpRequest();// 设置超时时间(毫秒)xhr.timeout = 2000;// 超时回调xhr.ontimeout = function () {alert("请求超时,请稍后重试!");};// 网络错误回调xhr.onerror = function () {alert("网络连接失败,请检查网络!");};xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {result.innerHTML = xhr.responseText;}};xhr.open("GET", "/JavaWeb_07/delay"); // 后端延迟 3 秒xhr.send();};
</script>
</html>
@WebServlet("/delay")
public class DelayServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {try {Thread.sleep(3000); // 模拟延迟} catch (InterruptedException e) {e.printStackTrace();}resp.getWriter().write("请求成功,但已延迟响应");}
}
  • xhr.timeout = 2000:设置 2 秒超时,单位毫秒。
  • ontimeout:超时触发。
  • onerror:网络异常触发(如断网、DNS 失败)。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-TimeoutAndOffline.html,点击按钮

在这里插入图片描述

超时回调函数触发。

将chrome浏览器做一个设置。

在这里插入图片描述

改成这样。

在这里插入图片描述

现在再次点击按钮。

在这里插入图片描述

网络错误回调函数触发。


1.6 取消请求

用户可能在请求未完成时切换页面或取消操作,此时应主动取消请求,避免资源浪费。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-取消请求</title>
</head>
<body><button>发送请求</button><button>取消请求</button><span id="result"></span>
</body>
<script>const btns = document.querySelectorAll("button");var result = document.getElementById("result");let xhr = null;// 发送请求btns[0].onclick = function () {xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {result.innerHTML = xhr.responseText;}};xhr.open("GET", "/JavaWeb_07/delay");xhr.send();};// 取消请求btns[1].onclick = function () {if (xhr) {xhr.abort(); // 取消请求result.innerHTML = "请求已取消";}};
</script>
</html>
  • xhr.abort():立即终止请求,onreadystatechange 仍会触发,但 status0
  • 适用于取消上传、搜索建议等场景。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-Abort.html

打开浏览器控制台,点击发送按钮后,3秒内点击取消。

点击发送按钮后,请求的Status显示pending

在这里插入图片描述

点击取消按钮后,请求的Status显示canceled

在这里插入图片描述


1.7 重复发送问题

用户快速多次点击按钮,可能触发多个重复请求,造成服务器压力或界面混乱。

解决方案:使用标识变量控制

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-防止重复发送</title>
</head>
<body><button id="btn">点击发送请求</button><span id="result"></span>
</body>
<script>var btn = document.getElementById("btn");var result = document.getElementById("result");let xhr = null;let isSending = false; // 标识是否正在发送请求btn.onclick = function () {// 如果正在发送,则取消上一次请求if (isSending) {xhr.abort();alert("上一次请求已取消");}xhr = new XMLHttpRequest();isSending = true; // 设置为正在发送xhr.onreadystatechange = function () {if (xhr.readyState === 4) {isSending = false; // 请求完成,重置标识}if (xhr.status === 200) {result.innerHTML = xhr.responseText;}};xhr.open("GET", "/JavaWeb_07/delay");xhr.send();};
</script>
</html>
  • isSending 变量防止并发请求。
  • 可选择“取消旧请求”或“忽略新请求”策略。

测试

访问http://localhost:8080/JavaWeb_07/Ajax-RepeatSend.html,快速点击请求按钮

在这里插入图片描述

可以看到快速请求同一个url时,只会响应最新的请求,之前的请求会被取消。

2、jQuery

jQuery 封装了原生 XMLHttpRequest,提供了更简洁、易用的 Ajax 方法。本节介绍三种常用方式:

  1. $.get() —— 发送 GET 请求
  2. $.post() —— 发送 POST 请求
  3. $.ajax() —— 通用型异步请求方法(高度可配置)

⚠️ 注意:jQuery 已逐渐被现代前端框架(如 Vue/React)取代,但在维护老项目或快速开发中仍广泛使用。

2.1 GET 请求:$.get()

用于向服务器获取数据,参数自动拼接在 URL 中。

语法格式

$.get(url, [data], [success], [dataType]);
参数说明
url请求地址(必填)
data要发送的数据对象(可选)
success成功回调函数:function(data, status, xhr)
dataType预期服务器返回的数据类型,如 'json', 'text'

案例:使用 $.get() 获取 JSON 数据

$('#btn-get').click(() => {$.get('/JavaWeb_07/jquery', {a: 100,b: 200}, (data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>`);$('#result').show();}, 'json');
});

说明

  • 参数 {a: 100, b: 200} 会自动拼接为:/JavaWeb_07/jquery?a=100&b=200
  • dataType: 'json' 表示期望返回 JSON,jQuery 会自动解析为 JS 对象
  • 适用于加载配置、用户信息等只读操作

2.2 POST 请求:$.post()

用于向服务器提交数据,数据放在请求体中。

语法格式

$.post(url, [data], [success], [dataType]);

参数含义与 $.get() 完全相同。

案例:使用 $.post() 提交表单类数据

$('#btn-post').click(() => {$.post('/JavaWeb_07/jquery', {a: 100,b: 200}, (data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>`);$('#result').show();}, 'json');
});

说明

  • 数据通过请求体发送,安全性高于 GET
  • jQuery 自动设置 Content-Type: application/x-www-form-urlencoded
  • 适用于登录、注册、提交订单等场景

2.3 通用型方法:$.ajax()

最灵活、功能最全的 Ajax 方法,支持所有配置项。

语法格式

$.ajax({url: '',            // 请求地址type: 'GET',        // 请求方式:GET、POST、PUT、DELETE 等data: {},           // 发送的数据(对象或字符串)dataType: 'json',   // 预期返回数据类型success: function(data) {},  // 成功回调error: function(xhr, status, err) {}, // 失败回调complete: function(xhr, status) {},  // 完成回调(无论成功失败)timeout: 3000,      // 超时时间(毫秒)headers: {},        // 自定义请求头async: true,        // 是否异步(默认 true)cache: false        // 是否缓存 GET 请求(false 可解决 IE 缓存)
});

案例:使用 $.ajax() 发送配置化请求

$('#btn-common').click(() => {$.ajax({url: '/JavaWeb_07/jquery',type: 'GET',data: {a: 100,b: 200},dataType: 'json',success: (data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>`);$('#result').show();},error: () => {console.log("请求失败!");alert("请求出错,请检查网络或服务器!");},complete: () => {console.log("请求结束(无论成功或失败)");},timeout: 2000,headers: {c: 300,d: 400}});
});

说明

  • type: 'GET' 可改为 'POST' 实现 POST 请求
  • headers 可用于传递 Token、版本号等自定义头信息
  • timeout 设置超时时间,避免请求卡死
  • complete 适合用于隐藏 loading 动画
  • cache: false 可防止 IE 缓存(jQuery 内部会自动加时间戳)

测试

@WebServlet("/jquery")
public class JQueryServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {String a = req.getParameter("a");System.out.println("a = " + a);String b = req.getParameter("b");System.out.println("b = " + b);// 设置响应格式为 JSON,编码 UTF-8resp.setContentType("application/json;charset=UTF-8");// 构造 JSON 字符串(注意:字符串中的双引号要转义)String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 获取输出流并写入响应resp.getWriter().write(json);}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-jQuery-GET-POST-Common</title><!--使用jQuery发送GET POST 的Ajax请求,通用型方法Ajax--><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div id="container" class="container" style="margin-top: 50px;"><h2>jQuery发送Ajax请求</h2><hr><button id="btn-get" class="btn btn-primary">GET</button><button id="btn-post" class="btn btn-success">POST</button><button id="btn-common" class="btn btn-info">通用型方法Ajax</button><div id="result" class="alert alert-success" style="margin-top: 20px;"><h4 id="result-title"></h4><p id="result-content"></p></div>
</div>
</body>
<script>$('button').eq(0).click(() => {$.get('/JavaWeb_07/jquery',{a: 100,b: 200},(data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>
`);$('#result').show();},'json')});$('button').eq(1).click(() => {//http://localhost:8080/$.post('/JavaWeb_07/jquery',{a: 100,b: 200},(data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>
`);$('#result').show();},'json')});$('button').eq(2).click(() => {$.ajax({//urlurl: '/JavaWeb_07/jquery',//参数data:{a: 100,b: 200},//请求方式type: 'GET',//响应数据类型dataType: 'json',//成功回调success: (data) => {console.log(data);$('#result-title').text(data.message);$('#result-content').html(`<li><strong>用户ID:</strong> ${data.userId}</li><li><strong>用户名:</strong> ${data.username}</li><li><strong>登录状态:</strong> ${data.success ? '✅ 成功' : '❌ 失败'}</li>
`);$('#result').show();},//超时时间timeout: 2000,//失败回调error: () => {console.log("出错了!!");},//完成回调complete: () => {console.log("请求结束!!");},//头信息headers: {c:300,d:400}});});
</script>
</html>

访问http://localhost:8080/JavaWeb_07/Ajax-jQuery-GET-POST-Common.html

在这里插入图片描述

点击GET,发送GET请求。

在这里插入图片描述

可以看到我们的url已经携带了我们设置的参数。

在这里插入图片描述

我们设置的dataType: 'json' ,jQuery自动帮我们在请求头上加上Accept: application/json

在这里插入图片描述

点击POST,发送POST请求。

可以看到,我们要携带的数据会自动加到请求体中。

在这里插入图片描述

点击通用型方法,发送GET请求。

可以看到我们在请求头中设置的信息。

在这里插入图片描述

3、Axios

Axios 是一个基于 Promise 的 HTTP 客户端,常用于浏览器和 Node.js 中发送异步请求。相比 jQuery 的 $.ajax,Axios 更现代、轻量、语义清晰,且原生支持 Promise 风格(.then().catch()),是目前主流前端框架(Vue/React)推荐使用的网络请求库。

Axios 的三大特点

  1. 基于 Promise:支持 .then().catch(),避免回调地狱
  2. 自动转换 JSON:请求/响应数据自动序列化/反序列化
  3. 拦截器支持:可统一处理请求头、错误、loading 等
  4. 浏览器兼容性好:支持所有现代浏览器
3.1 GET 请求:axios.get()

用于向服务器获取数据,参数通过 params 选项传递,会自动拼接到 URL 上。

语法格式

axios.get(url, {params: { /* URL 查询参数 */ },headers: { /* 请求头 */ }
})
.then(response => { /* 成功回调 */ })
.catch(error => { /* 失败回调 */ });

示例:使用 axios.get() 获取数据

btns[0].addEventListener("click", function () {axios.get('/JavaWeb_07/axios', {params: {a: 12345,b: 67890},headers: {"Content-Type": "application/json"}}).then(function (response) {console.log(response);result_title.textContent = response.data.message + 'get' || "操作成功";result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;}).catch(function (error) {console.log(error);});
});

说明

  • params 中的数据会自动拼接为:/JavaWeb_07/axios?a=12345&b=67890
  • headers 可自定义请求头(如认证 Token)
  • Content-Type: application/json 在 GET 请求中通常不必要(GET 没有请求体),但 Axios 允许设置
  • 响应数据在 response.data 中(不是 response 本身!)

⚠️ 注意:response 对象结构如下:

{data: { success: true, message: "登录成功", ... },  // 服务器返回的 JSONstatus: 200,statusText: "OK",headers: { ... },config: { ... }
}

3.2 POST 请求:axios.post()

用于向服务器提交数据,数据放在请求体中,通过 data 选项传递。

语法格式

axios.post(url, data, {params: { /* URL 参数 */ },headers: { /* 请求头 */ }
})
.then(response => { /* 成功 */ })
.catch(error => { /* 失败 */ });

示例:使用 axios.post() 提交登录数据

btns[1].addEventListener("click", function () {axios.post('/JavaWeb_07/axios', {username: "admin",password: "123456"}, {params: {a: 12345,b: 67890},headers: {"Content-Type": "application/json","height": "180cm","weight": "80kg"}}).then(function (response) {console.log(response);result_title.textContent = response.data.message + 'post' || "操作成功";result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;});
});

说明

  • 第二个参数 {username, password} 是请求体(Request Body)
  • params 仍可附加 URL 参数
  • headers 设置了自定义头(如身高体重),可用于调试或权限控制
  • Content-Type: application/json 表示发送的是 JSON 数据,后端需用 getReader()InputStream 读取

3.3 通用型方法:axios(config)

最灵活的方式,支持所有配置项,适合复杂请求。

语法格式

axios({method: 'GET' | 'POST' | 'PUT' | 'DELETE',url: '/api/xxx',params: { /* URL 参数 */ },data: { /* 请求体数据 */ },headers: { /* 请求头 */ },timeout: 5000
})
.then(response => { ... })
.catch(error => { ... });

示例:使用通用 axios() 发送 POST 请求

btns[2].addEventListener("click", function () {axios({method: "POST",url: '/JavaWeb_07/axios',params: {a: 12345,b: 67890},headers: {"height": "180cm","weight": "80kg"},data: {username: "admin",password: "123456"}}).then(response => {console.log(response);result_title.textContent = response.data.message + 'get' || "操作成功";result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;});
});

说明

  • 所有配置集中在一个对象中,结构清晰
  • data 是请求体,params 是 URL 参数
  • headers 可传递自定义信息
  • method 明确指定请求方式

测试

@WebServlet("/axios")
public class AxiosServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {String a = req.getParameter("a");System.out.println("a = " + a);String b = req.getParameter("b");System.out.println("b = " + b);// 设置响应格式为 JSON,编码 UTF-8resp.setContentType("application/json;charset=UTF-8");// 构造 JSON 字符串(注意:字符串中的双引号要转义)String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 获取输出流并写入响应resp.getWriter().write(json);}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-Axios</title><!--Axios--><script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.js"></script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div><div id="container" class="container" style="margin-top: 50px;"><h2>Axios发送Ajax请求</h2><hr><button id="btn-get" class="btn btn-primary">GET</button><button id="btn-post" class="btn btn-success">POST</button><button id="btn-common" class="btn btn-info">通用型方法Ajax</button><div id="result" class="alert alert-success" style="margin-top: 20px;"><h4 id="result-title"></h4><p id="result-content"></p></div></div>
</div>
</body>
<script>var btns = document.querySelectorAll("button");var result_title = document.getElementById("result-title");var result_content = document.getElementById("result-content");btns[0].addEventListener("click", function () {axios.get('/JavaWeb_07/axios', {//url参数信息params: {a: 12345,b: 67890},//请求头信息headers: {"Content-Type": "application/json"}}).then(function (response) {console.log(response);// 设置标题(比如显示 message)result_title.textContent = response.data.message + 'get' || "操作成功";// 设置内容(可以拼接多个字段)result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;}).catch(function (error) {console.log(error);}).finally(function () {// always executed});})btns[1].addEventListener("click", function () {axios.post('/JavaWeb_07/axios', {username: "admin", //请求体password: "123456"}, {//url 参数params: {a: 12345,b: 67890},//请求头参数headers: {"Content-Type": "application/json","height": "180cm","weight": "80kg"},}).then(function (response) {console.log(response);// 设置标题(比如显示 message)result_title.textContent = response.data.message + 'post' || "操作成功";// 设置内容(可以拼接多个字段)result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;})})btns[2].addEventListener("click", function () {axios({//请求方法method: "POST",//urlurl: '/JavaWeb_07/axios',//url参数params: {a: 12345,b: 67890},//请求头headers: {"height": "180cm","weight": "80kg"},//请求体data: {username: "admin",password: "123456"}}).then(response => {console.log(response);//响应状态码response.status;//响应状态字符串response.statusText;//响应头信息response.headers;//响应数据response.data;// 设置标题(比如显示 message)result_title.textContent = response.data.message + 'get' || "操作成功";// 设置内容(可以拼接多个字段)result_content.innerHTML = `状态: ${response.data.success ? '✅ 成功' : '❌ 失败'}<br>用户ID: ${response.data?.userId || '未知'}<br>用户名: ${response.data?.username || '未知'}`;})})
</script>
</html>

访问http://localhost:8080/JavaWeb_07/Ajax-Axios.html

在这里插入图片描述

点击GET,发送GET请求。params 中的数据会自动拼接为:/JavaWeb_07/axios?a=12345&b=67890响应数据在 response.data 中(不是 response 本身!)

在这里插入图片描述
在这里插入图片描述

点击POST,发送POST请求。第二个参数 {username, password} 是请求体(Request Body)params 仍可附加 URL 参数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

点击通用型方法,发送POST请求。

data 是请求体,params 是 URL 参数

在这里插入图片描述
在这里插入图片描述

4、Fetch

fetch() 是现代浏览器原生提供的 全局函数,用于发起网络请求。它基于 Promise,语法简洁,无需引入第三方库(如 jQuery 或 Axios),是当前 Web 开发中推荐使用的原生异步请求方式。

支持情况:所有现代浏览器(IE 不支持,需 polyfill)

Fetch 的核心特点

特性说明
原生支持浏览器内置,无需引入库
基于 Promise支持 .then().catch() 链式调用
分步处理响应需手动调用 .json().text() 等解析数据
灵活配置支持自定义 methodheadersbody
不自动判断 HTTP 状态即使返回 404/500,fetch 也不会自动 reject(需手动判断)

4.1 GET 请求:fetch(url, options)

用于从服务器获取数据,参数通过 URL 传递。

语法格式

fetch(url, {method: 'GET',headers: { /* 请求头 */ }
})
.then(response => response.json()) // 解析 JSON 响应
.then(data => { /* 使用数据 */ })
.catch(error => { /* 处理错误 */ });

示例:使用 fetch 发送 GET 请求

btns[0].addEventListener("click", function () {fetch('/JavaWeb_07/fetch', {method: 'GET',headers: {'Content-Type': 'application/json','height': '180','weight': '80'}}).then(response => {return response.json(); // 将响应体转为 JSON 对象}).then(data => {result_title.innerHTML = data.message;result_content.innerHTML = `状态: ${data.success ? '成功' : '失败'} <br>用户ID: ${data?.userId || '未知'} <br>用户名: ${data?.username || '未知'}`;});
});

说明

  • method: 'GET' 可省略(默认就是 GET)
  • headers 中的 Content-Type 在 GET 请求中通常无意义(GET 没有请求体),但可用于传递自定义信息
  • response.json() 返回一个 Promise,必须等待它解析完成后才能拿到真正的数据
  • URL 参数需手动拼接:/JavaWeb_07/fetch?a=123&b=456

如需传递参数,可改写为:

fetch('/JavaWeb_07/fetch?a=12345&b=67890', { method: 'GET', ... })

4.2 POST 请求:fetch() 提交数据

用于向服务器提交数据,数据通过 body 选项发送。

语法格式

fetch(url, {method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded' // 或 application/json},body: 'key=value&key2=value2' // 表单格式 或 JSON 字符串
})
.then(response => response.json())
.then(data => { /* 成功 */ })
.catch(error => { /* 失败 */ });

示例:使用 fetch 发送 POST 请求

btns[1].addEventListener("click", function () {fetch('/JavaWeb_07/fetch', {method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded','height': '180','weight': '80'},body: 'username=admin&password=123456' // 字符串形式的表单数据}).then(response => response.json()).then(data => {result_title.innerHTML = data.message;result_content.innerHTML = `状态: ${data.success ? '成功' : '失败'} <br>用户ID: ${data?.userId || '未知'} <br>用户名: ${data?.username || '未知'}`;});
});

测试

@WebServlet("/fetch")
public class FetchServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {// 获取 URL 参数(GET 或 POST 的 ?a=1&b=2)String a = req.getParameter("a");String b = req.getParameter("b");System.out.println("a = " + a);System.out.println("b = " + b);// 设置响应格式resp.setContentType("application/json;charset=UTF-8");// 返回 JSON 响应String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";resp.getWriter().write(json);}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-Fetch</title><!--Fetch(全局函数)--><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div><div id="container" class="container" style="margin-top: 50px;"><h2>Fetch发送Ajax请求</h2><hr><button id="btn-get" class="btn btn-primary">GET</button><button id="btn-post" class="btn btn-success">POST</button><div id="result" class="alert alert-success" style="margin-top: 20px;"><h4 id="result-title"></h4><p id="result-content"></p></div></div>
</div>
</body>
<script>var btns = document.querySelectorAll("button");var result_title = document.getElementById("result-title");var result_content = document.getElementById("result-content");btns[0].addEventListener("click", function () {fetch('/JavaWeb_07/fetch', {//请求方法method: 'GET',//请求头headers: {'Content-Type': 'application/json','height': '180','weight': '80'},}).then(response => {return response.json();}).then(data => {result_title.innerHTML = data.message;result_content.innerHTML = `状态: ${data.success ? '成功' : '失败'} <br>用户ID: ${data?.userId || '未知'} <br>用户名: ${data?.username || '未知'}`;});});btns[1].addEventListener("click", function () {fetch('/JavaWeb_07/fetch', {//请求方法method: 'POST',//请求头headers: {'Content-Type': 'application/json','height': '180','weight': '80'},//请求体body: 'username=admin&password=123456'}).then(response => {return response.json();}).then(data => {result_title.innerHTML = data.message;result_content.innerHTML = `状态: ${data.success ? '成功' : '失败'} <br>用户ID: ${data?.userId || '未知'} <br>用户名: ${data?.username || '未知'}`;});});
</script>
</html>

访问http://localhost:8080/JavaWeb_07/Ajax-Fetch.html

在这里插入图片描述


4.3 Fetch 响应处理详解

fetchresponse 对象提供多种方法解析响应体:

方法说明
response.json()解析为 JSON 对象(最常用)
response.text()解析为字符串
response.blob()解析为二进制 Blob(如图片)
response.formData()解析为 FormData
response.arrayBuffer()解析为 ArrayBuffer

必须调用其中之一,否则无法获取数据!


4.4 错误处理注意事项

fetch 只有在网络错误时才会进入 .catch()HTTP 状态码如 404、500 不会触发 catch

手动检查 response.ok

fetch('/JavaWeb_07/fetch').then(response => {if (!response.ok) {throw new Error(`HTTP ${response.status}: ${response.statusText}`);}return response.json();}).then(data => {// 处理数据}).catch(error => {console.error('请求失败:', error);});

四、跨域问题

在现代 Web 开发中,前端页面与后端 API 通常部署在不同的服务器上(如:前端 http://localhost:3000,后端 http://localhost:8080),此时浏览器会因 同源策略 阻止请求,这就是“跨域问题”。

1、同源

同源 指两个 URL 的以下三个部分完全相同:

组成部分示例
协议(Protocol)http://https://
域名(Host)localhostapi.example.com
端口(Port):8080:3000(默认 80/443 可省略)

同源示例

  • 页面:http://localhost:3000/index.html
  • 请求:http://localhost:3000/api/user 同源

跨域示例

页面地址请求地址原因
http://localhost:3000http://localhost:8080/api端口不同
http://localhost:3000https://localhost:3000/api协议不同
http://a.comhttp://b.com/api域名不同

🔐 同源策略(Same-Origin Policy):浏览器的安全机制,阻止 AJAX 请求跨域,但允许 <script><img><link> 等标签跨域加载资源。

2、跨域

当请求的 协议、域名、端口 任一不同,即为跨域。

跨域的典型错误

在浏览器控制台中,你会看到类似错误:

Access to fetch at 'http://localhost:8080/api' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这表示:浏览器阻止了该请求,因为后端没有明确允许跨域访问


解决跨域的常见方案

方案说明是否推荐
CORS(跨域资源共享)后端设置响应头允许跨域推荐(现代标准)
JSONP利用 <script> 标签可跨域的特性仅支持 GET,已过时
代理服务器前端或 Nginx 代理请求推荐(开发/生产通用)
WebSocket全双工通信,不受同源限制特定场景

3、jsonp

3.1 JSONP 原理

JSONP(JSON with Padding) 是一种“野路子”解决跨域的方法,利用了 <script> 标签不受同源策略限制的特性。

工作原理

  1. 前端定义一个 回调函数(如 handle(data)

  2. 动态创建 <script src="http://xxx/api?callback=handle"> 标签

  3. 后端接收到请求后,返回:

    handle({"success": true, "message": "登录成功"});
    
  4. 浏览器加载该 JS 脚本,自动执行 handle(...) 函数

  5. 前端在 handle 中处理数据

优点:兼容老浏览器(IE6+)
缺点:仅支持 GET 请求,安全性差(易受 XSS 攻击),已逐渐被淘汰


示例:JSONP 手动实现(原生 JS)

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-Jsonp原理</title>
</head>
<body>
<div><div id="result" style="width: 300px;height: 200px;border: blueviolet 1px solid"></div>
</div><!-- 定义回调函数 -->
<script>
function handle(data){var result = document.getElementById('result');result.innerHTML = data.success + " " + data.message+ " " + data.userId + " " + data.username;
}
</script><!-- 动态加载跨域脚本 -->
<script src="http://localhost:8080/JavaWeb_07/jsonp"></script>
</body>
</html>

后端 JsonpServlet 代码

@WebServlet("/jsonp")
public class JsonpServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {// 设置响应类型resp.setContentType("application/json;charset=UTF-8");// 构造 JSON 数据String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 返回:handle({ ... })resp.getWriter().write("handle(" + json + ")");}
}

在这里插入图片描述
在这里插入图片描述

关键点说明

步骤说明
handle(...)必须与前端定义的函数名一致
script 标签加载浏览器自动执行返回的 JS 代码
数据传递通过函数调用传参

3.2 jQuery 发送 JSONP 请求

jQuery 提供了更简洁的 JSONP 支持,自动处理回调函数名

示例:使用 $.getJSON() 发送 JSONP

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-Jsonp原理</title><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div><button id="btn">点击发送jsonp请求</button><div id="result" style="width: 300px;height: 200px;border: blueviolet 1px solid"></div>
</div>
</body>
<script>
$('#btn').click(function () {$.getJSON("http://localhost:8080/JavaWeb_07/jquery-jsonp?callback=?", function (data) {$('#result').html(`success:${data.success},message: ${data.message},userId: ${data.userId},username: ${data.username}`);});
});
</script>
</html>

后端 jQueryJsonpServlet (自动识别回调名)

@WebServlet("/jquery-jsonp")
public class jQueryJsonpServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {// 获取 jQuery 自动生成的回调函数名,如:jQuery1234567890123_1234567890String callback = req.getParameter("callback");resp.setContentType("application/javascript;charset=UTF-8");String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 返回:callbackName({"data": ...})resp.getWriter().write(callback + "(" + json + ")");}
}

说明

  • callback=?:jQuery 会自动替换 ? 为一个唯一的函数名(如 jQuery123...
  • 后端通过 req.getParameter("callback") 获取该函数名
  • 返回 callbackName({...}),jQuery 自动执行并调用你的回调函数

在这里插入图片描述


3.3 JSONP 的局限性
问题说明
仅支持 GET 请求无法发送 POST、PUT、DELETE
安全风险易受 XSS 攻击,返回的 JS 可能被篡改
无法捕获网络错误<script> 加载失败不会触发 catch
回调函数污染全局需手动清理,或使用一次性函数
不支持现代特性如进度条、超时控制、拦截器等

4、CORS

CORS(Cross-Origin Resource Sharing,跨域资源共享)是现代浏览器支持的一种标准跨域解决方案。它通过在服务器端设置特定的响应头,告诉浏览器允许来自指定源的跨域请求。

现代开发应优先使用 CORS,由后端设置响应头:

// 在 Servlet 中添加:
resp.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有域名
// resp.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"); // 指定域名
resp.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
resp.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");

✅ 优点:支持所有 HTTP 方法,安全可控,是 W3C 标准

4.1 工作原理
  • 前端发起 AJAX 请求
  • 浏览器自动在请求中添加 Origin
  • 服务器检查 Origin 是否在允许列表中
  • 如果允许,服务器返回带有 CORS 头的响应
  • 浏览器收到响应后,根据 CORS 头决定是否将数据暴露给前端 JavaScript
4.2 核心响应头
响应头作用示例
Access-Control-Allow-Origin允许哪些源访问http://localhost:63342*
Access-Control-Allow-Methods允许哪些 HTTP 方法GET, POST, PUT, DELETE
Access-Control-Allow-Headers允许客户端发送的请求头Content-Type, Authorization
Access-Control-Allow-Credentials是否允许携带凭据(如 Cookie)true
Access-Control-Max-Age预检请求缓存时间(秒)3600
Access-Control-Expose-Headers允许客户端访问的响应头Content-Type, X-Custom-Header

注意事项

  1. Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: true 不能同时使用
    • 如果需要携带 Cookie,Origin 必须是具体域名,不能是 *
  2. 简单请求无需预检,复杂请求会先发送 OPTIONS 预检请求
  3. 前端若需携带 Cookie,必须设置 xhr.withCredentials = true

测试

@WebServlet("/CORS")
public class CORSServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {//设置响应头,解决跨域//允许哪些源访问resp.setHeader("Access-Control-Allow-Origin", "*");//允许哪些请求方式访问resp.setHeader("Access-Control-Allow-Methods", "*");//请求结果缓存时间resp.setHeader("Access-Control-Max-Age", "3600");//允许哪些请求头访问resp.setHeader("Access-Control-Allow-Headers", "*");//允许携带验证信息  比如cookieresp.setHeader("Access-Control-Allow-Credentials", "false");//允许哪些头暴露resp.setHeader("Access-Control-Expose-Headers", "*");// 设置响应格式为 JSON,编码 UTF-8resp.setContentType("application/json;charset=UTF-8");// 构造 JSON 字符串(注意:字符串中的双引号要转义)String json = "{\"success\": true, \"message\": \"登录成功\", \"userId\": 1001, \"username\": \"zhangsan\"}";// 获取输出流并写入响应resp.getWriter().write(json);}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Ajax-CORS</title><!--CORS 解决跨域-->
</head>
<body>
<div><button>点击请求ajax</button><span id="result"></span>
</div>
</body>
<script>const btns = document.querySelectorAll("button");var result = document.getElementById("result");let xhr = null;btns[0].onclick = function () {//实例化一个XMLHttpRequest对象xhr = new XMLHttpRequest();//设置XMLHttpRequest对象的回调函数xhr.onreadystatechange = () => {if (xhr.readyState == 4 && xhr.status == 200) {result.innerHTML = xhr.responseText;result.style.color = "green";}};//设置发送请求的方式和请求的资源路径xhr.open("GET", "http://localhost:8080/JavaWeb_07/CORS");//发送请求xhr.send();}
</script>
</html>

在这里插入图片描述

总结

Ajax(Asynchronous JavaScript and XML) 是一种前端核心技术,它通过 XMLHttpRequest 或现代 Fetch API 实现页面与服务器的异步通信,无需刷新整个页面即可局部更新内容,显著提升用户体验,广泛应用于动态加载、表单提交、搜索建议等场景。

核心流程
事件触发 → 创建 XMLHttpRequest → 发送请求(GET/POST)→ 服务器处理 → 返回数据(JSON/XML)→ 回调函数处理响应 → DOM 局部更新。


跨域问题:浏览器基于同源策略(协议、域名、端口必须一致),默认禁止 AJAX 请求跨域资源,以防止恶意攻击。

主要解决方案

  1. CORS(Cross-Origin Resource Sharing,推荐)
    • 服务器通过设置响应头(如 Access-Control-Allow-Origin)主动授权跨域访问。
    • 支持所有 HTTP 方法(GET、POST 等),可携带 Cookie(需 withCredentials 配合)。
    • 复杂请求会先发送 OPTIONS 预检。
    • 现代开发的标准方案,安全、灵活、功能完整。
  2. JSONP(JSON with Padding,历史方案)
    • 利用 <script> 标签不受同源策略限制的特性,通过动态创建 script 标签加载数据,并用回调函数处理。
    • 仅支持 GET 请求,安全性较低,调试困难。
    • 已被 CORS 取代,仅用于兼容老系统。
http://www.dtcms.com/a/490603.html

相关文章:

  • 网站开发表格wordpress 语法编辑
  • 《零踩坑教程:基于 Trae 的高德地图 API 部署全流程解析》
  • 在Linux服务器上使用Jenkins和Poetry实现Python项目自动化
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段-二阶段(3):文法運用
  • [Sora] 数据管理 | `group_by_bucket`智能分桶 | DataloaderForVideo数据传输
  • 反向代理原理和服务转发实现方式
  • 中山企业网站多少钱爱奇艺做视频网站的
  • mapper.xml sql动态表查询配置
  • SQL Server 2019实验 │ 设计数据库的完整性
  • Leetcode每日一练--35
  • IDEA项目上传Gitee
  • 数据同步:Debezium监听,变更捕获实现?
  • 免费在线自助建站嵩明县住房和城乡建设局网站
  • PyTorch是什么?
  • 11年始终专注营销型网站龙岗召开企业服务大会
  • 11-触发器
  • dify 配置域名https访问
  • Fragment mWho 在registerForActivityResult 中作用
  • 告别插件堆砌!Neovim 配置“瘦身”实战:用 Mini.nvim 替换主流插件全过程
  • PyCharm 2025:最新使用图文教程!
  • 线性表之数组
  • 黄岩网站建设兼职无锡网站建设网络推广
  • 专业的食品行业网站开发叮当快药网站谁做的
  • Agent 时代的大模型演化:从 ChatGPT 到多智能体协作系统
  • uniapp uni.chooseImage+uni.uploadFile使用方法与详解
  • 云手机的魅力与优势
  • 关于 uni-app 与原生微信小程序中的生命周期 —— 一次“生命旅程”的解读
  • 方圆网通网站建设公司怎么做不用数据库的网站
  • uniapp 打开横竖屏。usb调试时可以横竖屏切换,但是打包发布后却不行?
  • 有些网站开发人员工具无反应老闵行小学排名