深入理解 Ajax 异步请求:从 XMLHttpRequest 到 Node.js HTTP 服务实践

前言

在现代 Web 开发中,前后端数据交互是最基础也是最重要的能力之一。当我们打开一个网页时,页面中的数据通常并不是直接写死在 HTML 中,而是通过网络请求从服务器动态获取。

例如:

  • 待办事项列表
  • 用户信息
  • 商品数据
  • 新闻内容

这些数据往往存储在服务器或数据库中,需要浏览器主动发起请求,再由服务器返回对应的数据。

如果每获取一次数据都重新加载整个页面,那么用户体验将会非常差。因此,Ajax 技术应运而生。

本文将通过一个完整的 TodoList 案例,从 HTTP 服务搭建开始,逐步讲解:

  • Ajax 的核心思想
  • JavaScript 异步机制
  • Event Loop 事件循环
  • JSON 数据格式
  • Node.js HTTP 服务
  • XMLHttpRequest 工作原理
  • DOM 动态渲染
  • Fetch 与 Async/Await

帮助大家建立完整的前后端通信知识体系。


一、什么是 Ajax

Ajax 全称:

Asynchronous JavaScript And XML

中文通常翻译为:

异步 JavaScript 与 XML

虽然名字中带有 XML,但现代开发中几乎已经全面使用 JSON 作为数据交换格式。

Ajax 的核心思想非常简单:

页面不刷新

↓

发送网络请求

↓

获取服务器数据

↓

局部更新页面

1.1 传统网页的工作方式

早期 Web 页面采用的是同步刷新模式。

例如点击一个超链接:

<a href="/news">新闻列表</a>

执行流程如下:

用户点击链接

↓

浏览器发送请求

↓

服务器返回新页面

↓

浏览器重新加载整个页面

即使只是更新一小部分内容,也必须重新加载整个页面。

这种方式存在两个明显问题:

  • 页面闪烁
  • 用户体验较差

1.2 Ajax 的出现

Ajax 技术出现后,浏览器获得了主动向服务器发送请求的能力。

执行流程变成:

用户操作页面

↓

发送异步请求

↓

服务器返回数据

↓

JavaScript更新DOM

↓

页面局部刷新

例如:

用户点击查看待办事项:

点击按钮

↓

请求 /todos

↓

获取JSON数据

↓

更新列表区域

↓

页面其余部分保持不变

这也是现代 Web 应用能够实现流畅交互的重要原因。


二、JavaScript 为什么需要异步

理解 Ajax 之前,必须先理解 JavaScript 的执行机制。


2.1 JavaScript 是单线程语言

JavaScript 只有一个主线程。

所谓单线程,就是:

同一时刻只能执行一个任务

例如:

console.log("A");

console.log("B");

console.log("C");

输出结果:

A
B
C

所有代码严格按照顺序执行。


2.2 如果没有异步会发生什么

假设浏览器发送一个网络请求:

const data = request();

服务器需要 5 秒钟才能返回结果。

如果 JavaScript 采用同步执行模式,那么:

请求发送

↓

等待5秒

↓

收到数据

↓

继续执行

在等待期间:

  • 页面无法响应
  • 按钮无法点击
  • 用户无法操作

整个浏览器都会被阻塞。

显然这是无法接受的。

因此 JavaScript 引入了异步机制。


2.3 同步与异步

同步执行:

console.log(1);
console.log(2);
console.log(3);

输出:

1
2
3

异步执行:

console.log(1);

setTimeout(() => {
    console.log(2);
}, 0);

console.log(3);

输出:

1
3
2

这里的关键问题是:

为什么明明先写了 setTimeout,却最后执行?

答案就在 Event Loop 中。


三、Event Loop 事件循环机制

JavaScript 并不会等待异步任务完成。

例如:

console.log("start");

setTimeout(() => {
    console.log("timeout");
}, 1000);

console.log("end");

输出:

start
end
timeout

3.1 执行过程分析

第一步:

console.log("start");

输出:

start

第二步:

setTimeout(...)

发现是异步任务。

JavaScript 不会等待。

而是交给浏览器处理。


第三步:

继续执行后续代码:

console.log("end");

输出:

end

第四步:

1 秒后计时结束。

回调函数进入任务队列。


第五步:

Event Loop 检测调用栈为空。

将回调函数取出执行。

输出:

timeout

3.2 Event Loop 工作流程

整个过程如下:

主线程(Call Stack)

↓

遇到异步任务

↓

交给浏览器(Web APIs)

↓

任务完成

↓

进入任务队列(Task Queue)

↓

Event Loop检测

↓

重新进入主线程执行

可以简化表示为:

Call Stack
    ↓
Web APIs
    ↓
Task Queue
    ↓
Event Loop
    ↓
Call Stack

3.3 Ajax 与 Event Loop 的关系

Ajax 请求本质也是异步任务。

例如:

xhr.send();

发送请求后:

浏览器开始请求服务器

↓

JavaScript继续执行

↓

服务器返回数据

↓

触发回调函数

↓

处理响应结果

因此:

发送请求
≠
等待响应

这一点非常重要。

很多初学者误以为:

xhr.send();

执行后程序会停下来等待服务器返回。

实际上并不会。

JavaScript 会继续执行后面的代码。


四、JSON 数据格式

浏览器和服务器之间交换数据时,最常使用的数据格式就是 JSON。

JSON 全称:

JavaScript Object Notation

即:

JavaScript对象表示法

4.1 JSON 为什么存在

例如:

const todo = {
    id:1,
    title:"过四六级",
    completed:false
};

这是一个 JavaScript 对象。

但是网络无法直接传输对象。

HTTP 能传输的本质上是:

字符串

或

二进制数据

因此需要将对象转换为字符串。

这个过程称为:

序列化(Serialization)

4.2 JSON.stringify()

作用:

JavaScript对象

↓

JSON字符串

例如:

const todo = {
    id:1,
    title:"过四六级"
};

console.log(
    JSON.stringify(todo)
);

输出:

{"id":1,"title":"过四六级"}

此时对象已经变成字符串,可以通过网络发送。


4.3 replace 参数

语法:

JSON.stringify(value, replace)

用于控制哪些属性参与序列化。

例如:

const todo = {
    id:1,
    title:"过四六级",
    completed:false
};

console.log(
    JSON.stringify(
        todo,
        ["title"]
    )
);

输出:

{"title":"过四六级"}

只有 title 被保留。


replace 还可以接收函数:

JSON.stringify(
    todo,
    function(key,value){
        return value;
    }
);

这种写法可以对序列化过程进行更加灵活的控制。


4.4 space 参数

语法:

JSON.stringify(
    value,
    null,
    space
);

用于控制缩进。

例如:

JSON.stringify(todo,null,2);

输出:

{
  "id": 1,
  "title": "过四六级"
}

开发阶段经常使用:

JSON.stringify(data,null,2);

因为格式更加清晰。

但在实际网络传输时通常不会添加缩进。

原因是:

缩进越多

↓

字符串越长

↓

传输体积越大

4.5 JSON.parse()

作用:

JSON字符串

↓

JavaScript对象

例如:

const str =
'{"id":1,"title":"过四六级"}';

const obj =
JSON.parse(str);

console.log(obj.title);

输出:

过四六级

4.6 stringify 与 parse 的对应关系

服务器发送数据:

对象

↓

JSON.stringify()

↓

JSON字符串

↓

网络传输

浏览器接收数据:

JSON字符串

↓

JSON.parse()

↓

对象

这是前后端通信过程中最基础也是最重要的一组 API。


五、使用 Node.js 搭建 HTTP 服务

在了解 Ajax 请求原理之前,我们首先需要拥有一个能够提供数据的服务器。

在实际开发中,前端页面的数据通常来自:

  • MySQL
  • PostgreSQL
  • MongoDB
  • Redis

等数据库。

但为了更专注于理解 HTTP 通信过程,本文使用 Node.js 原生 HTTP 模块模拟后端接口。


5.1 Node.js 内置 HTTP 模块

Node.js 提供了内置的 http 模块。

无需安装即可直接使用。

const http = require("http");

什么是模块(Module)

随着项目规模增大,不可能将所有代码都写在一个文件中。

例如:

project
│
├── app.js
├── user.js
├── todo.js
└── utils.js

每个文件负责不同功能。

这种开发方式称为:

模块化开发

CommonJS 模块规范

Node.js 早期采用 CommonJS 规范。

导入模块:

const http = require("http");

导出模块:

module.exports = data;

ES Module 模块规范

现代 JavaScript 推荐使用:

import http from "http";

导出:

export default data;

对应关系如下:

CommonJS ES Module
require import
module.exports export
Node早期方案 ECMAScript官方方案

5.2 创建 HTTP 服务器

代码如下:

const http = require("http");

http.createServer((req,res)=>{

});

这里调用了:

http.createServer()

用于创建一个 HTTP 服务。


createServer 的工作原理

服务器启动后:

等待请求

当浏览器访问:

http://localhost:3000

时:

浏览器发送请求

↓

Node接收请求

↓

执行回调函数

因此:

(req,res)=>{

}

并不是服务器启动时执行。

而是在收到请求时执行。

这一点需要特别注意。


5.3 req 与 res

createServer 回调函数有两个参数:

(req,res)

req(Request)

表示请求对象。

保存客户端发送过来的信息。

例如:

req.url

获取访问路径。


访问:

http://localhost:3000/

得到:

req.url
// "/"

访问:

http://localhost:3000/todos

得到:

req.url
// "/todos"

除了 url 之外,后续开发中还会经常使用:

req.method

请求方式。

例如:

GET
POST
PUT
DELETE

res(Response)

表示响应对象。

负责向浏览器返回数据。

例如:

res.end()

表示:

结束响应并返回数据

六、模拟 Todo 数据

为了模拟数据库查询结果。

我们定义一个数组:

const todos = [
    {
        id:1,
        title:"过四六级",
        completed:false
    },
    {
        id:2,
        title:"回家过节",
        completed:false
    }
];

这里很多初学者容易误解。

实际上:

这不是数据库

而只是:

内存中的普通数组

用于模拟数据库返回的数据。

真实项目中通常是:

SELECT * FROM todos;

查询数据库后再返回结果。


七、实现路由功能

完整代码:

if(req.url === "/"){
    res.end("hello world");
}

7.1 什么是路由

路由(Route)本质上就是:

不同URL

↓

对应不同处理逻辑

例如:

/

首页


/todos

任务列表


/users

用户列表


因此:

if(req.url === "/"){
}

实际上就是最简单的路由实现。


7.2 首页路由

if(req.url === "/"){
    res.end("hello world");
}

访问:

http://localhost:3000/

浏览器显示:

hello world

八、实现 Todo 接口

继续添加:

if(req.url === "/todos"){

}

当用户访问:

http://localhost:3000/todos

时进入对应逻辑。


8.1 为什么需要响应头

服务器返回数据时。

除了返回内容本身。

还会返回大量描述信息。

例如:

内容类型
编码方式
缓存策略
跨域规则

这些信息称为:

HTTP响应头

九、解决跨域问题(CORS)

代码:

res.setHeader(
    "Access-Control-Allow-Origin",
    "*"
);

9.1 什么是同源策略

假设:

前端运行在:

http://localhost:5500

后端运行在:

http://localhost:3000

虽然都在本机。

但是:

端口不同

浏览器认为:

不是同一个源

因此会触发:

跨域限制

浏览器默认禁止:

fetch("http://localhost:3000/todos");

直接访问。

控制台会报错:

CORS Error

9.2 Access-Control-Allow-Origin

为了解决跨域问题。

服务器需要主动告诉浏览器:

允许访问

代码:

res.setHeader(
    "Access-Control-Allow-Origin",
    "*"
);

表示:

允许所有来源访问

开发阶段经常使用:

"*"

生产环境通常会指定具体域名。

例如:

res.setHeader(
    "Access-Control-Allow-Origin",
    "https://example.com"
);

安全性更高。


十、设置响应数据类型

代码:

res.setHeader(
    "Content-Type",
    "application/json"
);

10.1 为什么需要 Content-Type

浏览器收到数据后。

必须知道:

返回内容是什么类型

否则无法正确解析。


常见类型:

HTML

text/html

普通文本

text/plain

JSON

application/json

图片

image/png

视频

video/mp4

因此:

application/json

告诉浏览器:

我返回的是JSON数据

十一、返回 Todo 数据

代码:

res.end(
    JSON.stringify(todos)
);

11.1 为什么不能直接返回对象

很多初学者会尝试:

res.end(todos);

实际上这是错误的。

原因在于:

HTTP 协议只能传输:

字符串

或

二进制数据

而:

[]
{}

属于 JavaScript 对象。

无法直接传输。


11.2 数据序列化过程

因此需要:

JSON.stringify()

进行序列化。

转换过程:

[
    {
        id:1,
        title:"过四六级"
    }
]

[
    {
        "id":1,
        "title":"过四六级"
    }
]

JSON字符串

通过HTTP发送

十二、监听端口

代码:

.listen(3000,()=>{
    console.log(
        "server is running on 3000 port"
    );
});

12.1 什么是端口

可以把:

IP地址

理解为:

一栋大楼

把:

Port

理解为:

房间号

例如:

127.0.0.1:3000

表示:

本机

↓

3000号端口

访问:

http://localhost:3000

实际上就是访问:

本机3000端口上的HTTP服务

十三、完整服务端代码

const http = require("http");

http.createServer((req,res)=>{

    const todos = [
        {
            id:1,
            title:"过四六级",
            completed:false
        },
        {
            id:2,
            title:"回家过节",
            completed:false
        }
    ];

    if(req.url === "/"){
        res.end("hello world");
    }

    if(req.url === "/todos"){

        res.setHeader(
            "Access-Control-Allow-Origin",
            "*"
        );

        res.setHeader(
            "Content-Type",
            "application/json"
        );

        res.end(
            JSON.stringify(todos)
        );
    }

}).listen(3000,()=>{
    console.log(
        "server is running on 3000 port"
    );
});

十四、使用 XMLHttpRequest 发起 Ajax 请求

服务端接口已经搭建完成。

接下来,我们开始编写前端代码,通过 Ajax 获取服务器中的 Todo 数据。

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <ul id="todos"></ul>

    <button id="btn">按钮</button>

    <script>

        console.log("start");

        document
            .getElementById("btn")
            .addEventListener("click",function(){
                console.log("点击按钮");
            });

        const xhr = new XMLHttpRequest();

        xhr.open(
            "GET",
            "http://localhost:3000/todos",
            true
        );

        console.log("start");

        xhr.onreadystatechange = function(){

            console.log(xhr.readyState);

            if(
                xhr.status === 200 &&
                xhr.readyState === 4
            ){

                const todos =
                    JSON.parse(
                        xhr.responseText
                    );

                document
                    .getElementById("todos")
                    .innerHTML =
                    todos
                        .map(todo =>
                            `<li>${todo.title}</li>`
                        )
                        .join("");

            }

        }

        console.log("end");

        xhr.send();

    </script>

</body>
</html>

十五、页面结构分析

首先观察页面结构:

<ul id="todos"></ul>

<button id="btn">按钮</button>

页面中只有两个元素:

一个用于显示任务列表:

<ul id="todos"></ul>

一个用于演示事件机制:

<button id="btn">按钮</button>

15.1 Todos 容器

初始状态:

<ul id="todos"></ul>

页面中没有任何数据。


当服务器返回数据后:

<ul id="todos">
    <li>过四六级</li>
    <li>回家过节</li>
</ul>

内容会动态生成。

这正是 Ajax 的核心思想:

数据驱动页面

而不是:

把数据写死在HTML中

十六、事件注册机制

代码:

document
.getElementById("btn")
.addEventListener("click",function(){
    console.log("点击按钮");
});

16.1 为什么需要事件监听

浏览器无法提前知道:

用户什么时候点击按钮

因此需要提前注册事件。

执行流程:

注册事件

↓

等待用户操作

↓

事件触发

↓

执行回调函数

16.2 addEventListener 参数分析

第一个参数:

"click"

表示事件类型。


常见事件:

"click"

点击事件


"input"

输入事件


"change"

内容改变事件


"submit"

表单提交事件


第二个参数:

function(){

}

回调函数。

只有事件发生时才会执行。


十七、Ajax 的发展历史

在学习 XMLHttpRequest 之前。

有必要了解 Ajax 技术的发展过程。


17.1 Web 1.0 时代

早期网页主要依赖:

<a href="">

和:

<form>

进行页面跳转。

执行流程:

点击链接

↓

浏览器发送请求

↓

服务器返回新页面

↓

浏览器重新刷新

整个页面都会被重新加载。


17.2 Ajax 时代

XMLHttpRequest 出现后。

浏览器获得了主动请求服务器的能力。

执行流程变成:

发送请求

↓

获取数据

↓

更新页面局部区域

↓

无需刷新页面

这就是 Ajax 的本质。


17.3 Fetch 时代

现代浏览器逐渐采用:

fetch()

代替:

XMLHttpRequest

虽然 API 不同。

但核心思想完全一致:

发送HTTP请求

↓

获取服务器数据

↓

更新页面

十八、创建 XMLHttpRequest 对象

代码:

const xhr = new XMLHttpRequest();

18.1 XMLHttpRequest 是什么

可以理解为:

浏览器中的HTTP客户端

专门负责:

  • 建立连接
  • 发送请求
  • 接收响应

创建对象后:

xhr

就拥有了完整的 HTTP 通信能力。


十九、配置请求

代码:

xhr.open(
    "GET",
    "http://localhost:3000/todos",
    true
);

19.1 第一个参数

"GET"

请求方式。


常见请求方式:

GET

获取数据

GET /todos

POST

创建数据

POST /todos

PUT

修改数据

PUT /todos/1

DELETE

删除数据

DELETE /todos/1

19.2 第二个参数

"http://localhost:3000/todos"

请求地址。

对应服务端:

if(req.url === "/todos")

19.3 第三个参数

true

表示异步请求。


如果写成:

false

则表示同步请求。

浏览器会被阻塞。

现代开发已经基本废弃同步请求。


二十、send() 发送请求

代码:

xhr.send();

作用:

正式发送HTTP请求

很多初学者认为:

xhr.send();

执行后程序会停下来等待。

实际上不会。


例如:

console.log("A");

xhr.send();

console.log("B");

输出:

A
B

说明:

请求发送

≠

等待响应

这正是 Ajax 的异步特性。


二十一、请求状态监听

代码:

xhr.onreadystatechange = function(){

}

21.1 什么是 onreadystatechange

每当请求状态发生变化。

浏览器都会触发:

onreadystatechange

回调函数。


因此:

console.log(xhr.readyState);

会输出多个数字。

因为请求过程经历了多个阶段。


二十二、readyState 状态详解

XMLHttpRequest 一共有五种状态。


0:UNSENT

对象创建完成

例如:

const xhr =
new XMLHttpRequest();

1:OPENED

已经调用open()

例如:

xhr.open(...)

2:HEADERS_RECEIVED

已经收到响应头

服务器已经响应。

但数据还未接收完成。


3:LOADING

正在接收数据

数据不断从服务器传输过来。


4:DONE

请求完成

数据接收结束。

可以开始处理结果。


因此:

console.log(xhr.readyState);

通常会看到:

1
2
3
4

或者:

2
3
3
4

具体取决于网络环境。


二十三、HTTP 状态码

代码:

xhr.status === 200

表示:

HTTP响应状态码

常见状态码:

200

OK

请求成功


404

Not Found

资源不存在


500

Internal Server Error

服务器内部错误


因此:

xhr.status === 200 &&
xhr.readyState === 4

表示:

请求成功完成

此时可以安全处理数据。


二十四、解析服务器返回的数据

代码:

const todos =
JSON.parse(
    xhr.responseText
);

24.1 responseText 是什么

服务器返回:

[
    {
        "id":1,
        "title":"过四六级"
    }
]

很多人误以为:

responseText

得到的是数组。

实际上不是。


得到的是:

JSON字符串

例如:

'[{"id":1,"title":"过四六级"}]'

本质仍然是字符串。


24.2 JSON.parse

因此需要:

JSON.parse()

进行反序列化。

转换过程:

JSON字符串

↓

JSON.parse()

↓

JavaScript对象

这与服务端的:

JSON.stringify()

形成对应关系。


服务端:

对象

↓

JSON.stringify()

↓

字符串

浏览器:

字符串

↓

JSON.parse()

↓

对象

二十五、动态渲染页面

获取数据后:

todos.map(
    todo =>
    `<li>${todo.title}</li>`
)

假设数据:

[
    {
        title:"过四六级"
    },
    {
        title:"回家过节"
    }
]

生成:

[
    "<li>过四六级</li>",
    "<li>回家过节</li>"
]

随后:

.join("")

转换为:

<li>过四六级</li><li>回家过节</li>

最终:

document
.getElementById("todos")
.innerHTML = ...

更新页面。

浏览器渲染结果:

• 过四六级

• 回家过节

二十六、完整请求流程分析

到这里,我们已经完成了一个完整的 Ajax 通信案例。

但是对于初学者来说,最容易混乱的地方在于:

到底是谁先执行?
谁在等待?
数据又是怎么回来的?

下面我们从用户打开页面开始,梳理整个请求流程。


26.1 页面加载

浏览器加载:

index.html

开始执行 JavaScript:

console.log("start");

输出:

start

接着注册按钮点击事件:

document
.getElementById("btn")
.addEventListener(...)

此时:

事件注册完成

↓

等待用户点击

但并不会立即执行回调函数。


26.2 创建 XMLHttpRequest 对象

执行:

const xhr = new XMLHttpRequest();

浏览器创建一个 HTTP 请求对象。

此时:

readyState = 0

26.3 配置请求

执行:

xhr.open(
    "GET",
    "http://localhost:3000/todos",
    true
);

请求配置完成。

状态变为:

readyState = 1

26.4 注册状态监听

执行:

xhr.onreadystatechange = function(){

}

注册回调函数。

此时浏览器开始监听请求状态变化。


26.5 发送请求

执行:

xhr.send();

浏览器正式向服务器发送请求。

注意:

发送请求

≠

等待响应

请求发送后。

JavaScript 会继续向下执行:

console.log("end");

输出:

end

26.6 Node服务器接收请求

服务器收到:

GET /todos

请求。

进入:

if(req.url === "/todos")

对应逻辑。


然后返回:

JSON.stringify(todos)

生成的 JSON 字符串。


26.7 浏览器收到响应

收到响应后:

onreadystatechange

被触发。

状态依次变化:

2

↓

3

↓

4

当:

xhr.readyState === 4

并且:

xhr.status === 200

说明请求成功完成。


26.8 解析 JSON 数据

执行:

JSON.parse(
    xhr.responseText
)

完成反序列化。

转换过程:

JSON字符串

↓

JavaScript对象

26.9 更新页面

执行:

innerHTML = ...

更新 DOM。

浏览器重新渲染页面。

最终显示:

过四六级

回家过节

二十七、为什么 Ajax 能实现局部刷新

很多初学者会产生一个疑问:

为什么 Ajax 请求不会刷新整个页面?

原因在于:

Ajax 请求获取的是:

数据

而不是:

新的HTML页面

传统网页:

请求

↓

返回HTML

↓

重新渲染整个页面

Ajax:

请求

↓

返回JSON

↓

JavaScript处理数据

↓

更新部分DOM

因此:

页面无需重新加载

这就是局部刷新的本质。


二十八、Fetch:现代 Ajax 方案

虽然 XMLHttpRequest 仍然能够工作。

但现代开发更推荐:

fetch()

例如:

fetch(
    "http://localhost:3000/todos"
)
.then(res => res.json())
.then(data => {
    console.log(data);
});

代码更加简洁。

逻辑也更加清晰。


Fetch 与 XMLHttpRequest 对比

XMLHttpRequest

const xhr = new XMLHttpRequest();

xhr.open(...);

xhr.onreadystatechange = function(){

};

xhr.send();

Fetch

fetch(url)
.then(...)
.then(...)

明显更加简单。


二十九、Async 与 Await

现代项目中最推荐的写法是:

async/await

例如:

async function getTodos(){

    const res =
        await fetch(
            "http://localhost:3000/todos"
        );

    const data =
        await res.json();

    console.log(data);

}

相比 Promise:

fetch(...)
.then(...)
.then(...)
.then(...)

Async/Await 具有以下优势:

  • 更接近同步代码
  • 可读性更高
  • 更容易维护
  • 错误处理更统一

因此已经成为当前前端开发主流方案。


总结

本文通过一个完整的 TodoList 案例,系统学习了 Ajax 的核心知识。

主要内容包括:

  • Ajax 的本质与作用
  • JavaScript 单线程模型
  • Event Loop 事件循环
  • JSON.stringify 与 JSON.parse
  • Node.js HTTP 服务
  • 路由机制
  • CORS 跨域问题
  • XMLHttpRequest 工作原理
  • readyState 状态变化
  • HTTP 状态码
  • DOM 动态渲染
  • Fetch 与 Async/Await

通过这个案例,我们实际上已经完成了一次完整的前后端通信实践:

浏览器

↓

Ajax请求

↓

Node服务器

↓

JSON数据

↓

浏览器解析

↓

DOM渲染

↓

页面更新

理解这一套流程之后,再学习 Express、数据库、RESTful API、Vue、React 等技术时,就能够更加清晰地理解它们背后的运行原理。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐