Ajax 传输 JSON 与 XML:千古前端教程的数据交换与解析实战
Ajax 传输 JSON 与 XML:千古前端教程的数据交换与解析实战
导读
在 Ajax 应用中,服务器返回的数据主要有两种承载格式:JSON 与 XML。本篇是「千古前端图文教程」异步编程系列的核心实战章节,承接 《02-Ajax 入门和发送 http 请求》 中关于 XMLHttpRequest 对象五步请求的基础,深入讲解如何在浏览器端接收、解析并渲染 JSON 与 XML 数据。读完本篇,你将掌握 JSON 与 XML 两种格式的语法规则、JavaScript 与 PHP 两侧的序列化/反序列化方法,以及通过 XMLHttpRequest 完整请求并解析这两种数据格式的前后端联调方案。
一、前置知识:Ajax 的数据从哪来
在进入 JSON 与 XML 之前,先回顾一下 Ajax 的基础链路。Ajax(Asynchronous JavaScript And XML)的核心是 JS 对象 XMLHttpRequest,发送一次请求需要五步:
- 创建异步对象
new XMLHttpRequest(); - 用
open(method, url, async)设置请求参数; - 用
send()发送请求; - 注册
onreadystatechange事件; - 服务端响应后,通过判断
readyState == 4 && status == 200获取返回的数据。
其中,与数据格式直接相关的两个属性是(详见 02-Ajax 入门和发送 http 请求):
responseText:获得字符串形式的响应数据;responseXML:获得 XML 形式的响应数据。
如果响应的是普通字符串(包括 JSON 字符串),就使用 responseText;如果响应的是 XML,则使用 responseXML。本篇的所有实战都将围绕这两个属性展开。
二、Ajax 传输 JSON
2.1 JSON 的语法
JSON(JavaScript Object Notation):是 ECMAScript 的子集,作用是进行数据的交换。相比其他数据格式,JSON 语法更为简洁,网络传输、机器解析都更为迅速。
语法规则:
- 数据在键值对中;
- 数据由逗号分隔;
- 花括号保存对象;
- 方括号保存数组。
数据类型:
- 数字(整数或浮点数);
- 字符串(在双引号中);
- 逻辑值(true 或 false);
- 数组(在方括号中);
- 对象(在花括号中);
- null。
示例:
// 对象
{
"name":"fox",
"age":"18",
"sex":"true",
"car":null
}
// 数组
[
{
"name":"小小胡",
"age":"1"
},
{
"name":"小二胡",
"age":"2"
}
]
注意:JSON 中字符串必须使用双引号,键名同样使用双引号包裹,这与 JavaScript 对象字面量的写法略有差异。
2.2 JavaScript 中:json 字符串 <--> js 对象
基本上,所有的语言都有将 json 字符串转化为该语言对象的语法。在 JS 中,主要通过 JSON 内置对象的两个方法完成双向转换:
(1)JSON.parse():将 JSON 字符串转化为 js 对象。
// 将 JSON 字符串格式化为 js 对象
var jsObj = JSON.parse(ajax.responseText);
JSON.parse() 会严格校验传入的字符串,如果字符串不符合 JSON 语法(例如键名漏掉双引号、末尾多一个逗号),会抛出 SyntaxError,因此在实际项目中通常建议用 try...catch 包裹。
(2)JSON.stringify():将 JS 对象转化为 JSON 字符串。
var Obj = {
name: 'fox',
age: 18,
skill: '撩妹',
};
console.log(Obj);
// 将 js 对象格式化为 JSON 字符串
var jsonStr = JSON.stringify(Obj);
JSON.stringify() 常用于向服务器提交数据前的序列化,也常用于调试打印——本项目其他章节(如 04-JavaScript基础/18-数组简介.md、19-数组的常见方法.md)中大量使用 console.log(JSON.stringify(arr)) 来直观查看数组内容,就是这个方法最常见的用法。
2.3 PHP 中:json 字符串 <--> 变量
服务端语言同样具备 JSON 双向转换能力。以 PHP 为例:
json_decode()方法:将json字符串转化为变量;json_encode()方法:将变量转化为json字符串。
代码举例:
<?php
header("Content-Type:text/html;charset=utf-8");
// json字符串
$jsonStr = '{"name":"itcast","age":54,"skill":"歌神"}';
// 字符串转化为 php对象
print_r(json_decode($jsonStr));
echo "<br>";
// php数组
$arrayName = array('name' =>'littleFox' ,'age' => 13 );
// php对象 转化为 json字符串
print_r(json_encode($arrayName));
?>
输出结果:
stdClass Object ( [name] => itcast [age] => 54 [skill] => 歌神 )
{"name":"littleFox","age":13}
从输出可以看到,json_decode() 默认把 JSON 对象解析为 PHP 的 stdClass 对象,而 json_encode() 会把 PHP 数组序列化为标准的 JSON 字符串——这正是 Ajax 前后端联调时数据流通的完整闭环:PHP 端用 json_encode() 把数组转成 JSON 字符串输出,浏览器端用 JSON.parse() 把 responseText 还原成 JS 对象。
2.4 ajax 请求解析 json(完整举例)
下面通过三个文件,演示一次完整的「PHP 读取 JSON 文件 → Ajax 请求 → 解析并渲染」流程。
(1)Person.json(存放数据的 JSON 文件):
{
"name": "小强",
"skill": "砍树",
"friend": "老板"
}
(2)myJson.php(服务端脚本:读取 json 文件并原样返回):
<?php
// 读取json文件 并返回即可
echo file_get_contents('info/Person.json');
?>
这里用到了 PHP 内置的 file_get_contents() 方法读取同目录下 info/Person.json 文件的内容,并通过 echo 直接输出。由于 JSON 本身就是字符串,不需要额外设置响应头,浏览器端按字符串接收即可。
(3)getJson.html(前端页面:发起 Ajax 请求,解析并渲染数据):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<h1>获取 json 数据</h1>
<input type="button" value="获取json" id="btnJson" />
</body>
</html>
<script type="text/javascript">
// 获取的是一个 如果要获取多个
// document.querySelectorAll(selector)
document.querySelector('#btnJson').onclick = function () {
var ajax = new XMLHttpRequest();
ajax.open('get', 'myJson.php');
ajax.send();
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
// json 字符串 是字符串 所以我们可以 通过 responseText获取
console.log(ajax.responseText);
// 转化为 js对象
var jsObj = JSON.parse(ajax.responseText);
console.log(jsObj);
// 拼接ul s
var str = '';
str += '<ul>';
str += '<li>' + jsObj.name + '</li>';
str += '<li>' + jsObj.skill + '</li>';
str += '<li>' + jsObj.friend + '</li>';
str += '</ul>';
// 设置到界面上
document.body.innerHTML = str;
}
};
};
</script>
要点解读:
- 由于 JSON 在网络上传输时本质上就是一串文本,所以服务端返回的 JSON 内容统一通过
responseText获取; - 拿到字符串后,必须用
JSON.parse()转成 JS 对象,才能用jsObj.name这样的点语法读取属性; - 最后通过字符串拼接生成
<ul>列表,写入document.body.innerHTML完成页面渲染; - 这里的判断条件
readyState == 4 && status == 200是 Ajax 数据完整返回的标准判据:readyState为 4 表示请求已完成且响应就绪,status为 200 表示请求成功(这两个状态码的详细含义见 02-Ajax 入门和发送 http 请求)。
三、Ajax 传输 XML
3.1 XML 语法
XML(Extensible Markup Language):可扩展标记语言。与 JSON 不同,XML 的语法要点如下。
1、XML 声明:
<?xml version="1.0" encoding="UTF-8"?>
第一行的声明,指定了 XML 版本(1.0)以及使用的编码。声明必须放在 XML 文档的第一行。
2、自定义标签:
XML 中没有默认的标签,所有的标签都是我们自己定义的。例如:
<fox></fox>
<name></name>
注意:XML 中没有单标签,都是双标签,即必须成对出现(<标签></标签>),标签必须正确嵌套。
3、根节点:
XML 中必须要有一个根节点,所有的子节点都放置在根节点下。例如:
<root1>
<name></name>
</root1>
XML 文档有且仅有一个根节点,它是整个文档的顶层容器。
3.2 XML 解析
因为 XML 就是标签,所以我们可以直接用解析 Dom 元素的方法解析 XML。浏览器会将 XML 文档解析为一个 document 类型的节点树,天然支持 DOM 查询 API。
解析过程:
(1)html 部分(包含 xml 片段):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<person id="personXML">
<name>fox</name>
<age>18</age>
<skill>小花花</skill>
</person>
</body>
</html>
(2)解析 xml:
<script type="text/javascript">
var xmlObj = document.getElementById('personXML');
var name = xmlObj.getElementsByTagName('name')[0].innerHTML;
console.log(name);
</script>
解析思路:先用 getElementById('personXML') 定位 XML 的根节点,再通过 getElementsByTagName('name')[0] 获取第一个 name 标签节点,读取其 .innerHTML 得到标签内的文本内容。整个过程与操作普通 HTML DOM 完全一致。
3.3 ajax 请求解析 xml(完整举例)
与 JSON 请求不同,服务端返回 XML 时必须显式设置响应头 Content-Type 为 text/xml,浏览器才能正确识别并按 XML 文档解析,从而让 responseXML 属性可用。
(1)get_xml.php(服务端脚本:里面包含了 xml 文件):
<?php
// 设置 返回的为 xml
header('content-type:text/xml; charset= utf-8');
// 读取xml文件 并返回
echo file_get_contents('info/star.xml');
?>
上方代码解释:
- PHP 自带了读取 xml 文件的方法(
file_get_contents()); - 在 PHP 中,如果要使用 XML 传输数据,则需要使用
header()设置返回的内容为 XML。这里header('content-type:text/xml; charset=utf-8')的作用是向浏览器发送响应报文头,声明响应体是 XML 格式。关于header()函数设置响应头的更多用法(如设置编码、页面跳转、刷新间隔),可以参见 00-服务器分类及PHP入门.md 中的「php 中的 header() 函数」小节。
(2)get_xml.html(Ajax 请求,获取并解析 xml):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<input type="button" value="获取XMl数据" id="getXML" />
</body>
</html>
<script type="text/javascript">
document.querySelector('#getXML').onclick = function () {
var ajax = new XMLHttpRequest();
ajax.open('get', 'get_XMl.php');
ajax.send();
ajax.onreadystatechange = function () {
if (ajax.readyState == 4 && ajax.status == 200) {
// 如果 返回的是 xml文件
console.log(ajax.responseText);
// 异步 对象中 有另外一个属性 用来专门获取 xml
// xml对象 在浏览器段 就是一个 document对象
// 解析时 可以直接使用 querySelector 或者 getElementById等等 document对象 有的语法
console.log(ajax.responseXML);
console.log(ajax.responseXML.querySelector('kuzi').innerHTML);
// 下面这个 页面文档对象 如果要获取某个标签
console.log(window.document);
}
};
};
</script>
要点解读:
ajax.responseText拿到的是 XML 的原始字符串,可以看到标签形式的文本内容;ajax.responseXML拿到的是浏览器解析后的 XML Document 对象,它和window.document一样是document类型,因此可以直接使用querySelector()、getElementById()、getElementsByTagName()等 DOM 查询语法来定位节点;ajax.responseXML.querySelector('kuzi').innerHTML演示了用选择器直接取出某个子标签的文本内容。
3.4 responseText 与 responseXML 的适用场景
结合两个实战可以总结出规律:
| 响应类型 | 获取属性 | 解析方式 | 服务端要求 |
|---|---|---|---|
| JSON | responseText |
JSON.parse() 转成 JS 对象 |
输出合法 JSON 字符串即可 |
| XML | responseXML |
直接当作 document 对象,用 DOM API 查询 | 必须用 header('content-type:text/xml; charset=utf-8') 声明 XML |
如果服务端没有正确设置 XML 的响应头,responseXML 可能返回 null,此时只能退而求其次用 responseText 拿到字符串、再用 DOMParser 自行解析。因此,前后端对数据格式的约定(响应头、编码、结构)是整个联调能否成功的关键。
四、JSON 与 XML 的对比与选型
通过本篇两个实战,可以总结出两种格式的核心差异:
JSON 的优势:
- 语法简洁,体积更小,网络传输和机器解析更快(这正符合 2.1 节所说的设计初衷);
- 与 JavaScript 对象天然接近,
JSON.parse()/JSON.stringify()双向转换零成本; - 所有主流语言(PHP 的
json_decode/json_encode等)都内置了完整的序列化支持。
XML 的优势:
- 可扩展性强,标签语义化,适合表达层级复杂的文档型数据;
- 有严格的语法约束(唯一根节点、双标签、声明),可配合 DTD/Schema 做数据校验;
- 在 RSS 订阅、配置文件、SVG 等领域仍是标准格式。
在当前的 Web 开发实践中,接口数据交换几乎都以 JSON 为主,XML 更多出现在文档类场景。另外需要注意:当接口数据涉及跨域时,浏览器默认不允许 Ajax 跨域获取数据,常见的解决方案有 JSONP(利用 <script> 标签的 src 可跨域特性,由服务端返回预定义的函数调用)等,这部分内容可以继续阅读本系列的 《04-同源和跨域》。
五、常见问题排查清单
结合本篇三个示例,罗列几个最容易踩的坑:
JSON.parse()报错:服务端返回的不是合法 JSON(如键名用了单引号、包含注释、出现尾逗号),或返回了 HTML 错误页。先用console.log(ajax.responseText)检查原始字符串。jsObj.name拿到undefined:JSON 键名与代码中读取的属性名不一致(注意 JSON 键名区分大小写),或 JSON 实际是数组而非对象。responseXML为null:服务端没有用header('content-type:text/xml; charset=utf-8')声明 XML 响应头,导致浏览器没有按 XML 解析响应体。- 中文乱码:XML 声明中的
encoding、服务端header()中的charset、页面的<meta charset>三者编码必须统一为 UTF-8。 readyState判断遗漏:务必在onreadystatechange中同时判断readyState == 4 && status == 200,否则可能在数据尚未完整返回时就提前取值。
小结
本篇以「千古前端图文教程」中 Ajax 传输 JSON 与 XML 的实战为主线,完整覆盖了两种数据格式的语法规则、JavaScript 与 PHP 两侧的转换方法,以及基于 XMLHttpRequest 的前后端联调示例。掌握 JSON.parse / JSON.stringify、PHP 的 json_decode / json_encode,以及 responseText / responseXML 两个属性的正确使用场景,你就能独立完成绝大多数 Ajax 数据交互需求。后续进阶可继续学习本系列的 《05-回调函数》 与 《06-Promise 入门详解》,用更优雅的方式组织异步请求逻辑。