核心知識點速覽
- POST 必須設置請求頭:
Content-Type: application/x-www-form-urlencoded,否則服務端無法解析請求體。
- XML 響應需正確 Content-Type:
Content-Type: text/xml; charset=gb2312(或 utf-8),並禁用緩存。
- MySQL 中文亂碼鐵律:查詢前執行
SET character_set_connection=gb2312, character_set_results=gb2312, character_set_client=binary。
- 跨瀏覽器 XML 解析:IE 用
ActiveXObject("MSXML2.DOMDocument").loadXML(),標準瀏覽器用 responseXML。
客戶端完整代碼
<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>省市縣三級聯動演示</title>
<style> select { width: 120px; } </style>
<script>
var currentSelectId = "";
var xmlHttp;
// 1. 創建跨瀏覽器 XMLHttpRequest
function createXHR() {
if (window.ActiveXObject) return new ActiveXObject("Microsoft.XMLHTTP");
return new XMLHttpRequest();
}
// 2. 發送 POST 請求
function ajaxCall(id) {
xmlHttp = createXHR();
if (!xmlHttp) return;
var url = "chuli.php";
var data = "id=" + encodeURIComponent(id);
xmlHttp.open("POST", url, true);
xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xmlHttp.onreadystatechange = handleResponse;
xmlHttp.send(data);
}
// 3. 統一響應處理:XML 解析跨瀏覽器
function handleResponse() {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var items = getXMLData("res");
var sel = document.getElementById(currentSelectId);
sel.length = 0; // 清空選項
for (var i = 0; i < items.length; i++) {
var optId = items[i].getElementsByTagName("id")[0].firstChild.nodeValue;
var optVal = items[i].getElementsByTagName("name")[0].firstChild.nodeValue;
var opt = document.createElement("option");
opt.value = optId;
opt.text = optVal;
sel.appendChild(opt);
}
}
}
// 4. 跨瀏覽器 XML 節點獲取
function getXMLData(tagName) {
if (window.ActiveXObject) { // IE
var doc = new ActiveXObject("MSXML2.DOMDocument");
doc.loadXML(xmlHttp.responseText);
return doc.getElementsByTagName(tagName);
}
return xmlHttp.responseXML.getElementsByTagName(tagName); // 標準
}
// 5. 業務調用鏈
function loadProvinces() {
currentSelectId = "Province";
ajaxCall("1"); // 根節點 ID
}
function loadCities() {
currentSelectId = "City";
document.getElementById("County").length = 0;
ajaxCall(document.getElementById("Province").value);
}
function loadCounties() {
currentSelectId = "County";
if (document.getElementById("City").length > 0)
ajaxCall(document.getElementById("City").value);
}
window.onload = loadProvinces;
</script>
</head>
<body>
<form>
<select id="Province" onchange="loadCities()"></select>
<select id="City" onchange="loadCounties()"></select>
<select id="County" name="xian"></select>
</form>
</body></html>
服務端 PHP (chuli.php)
<?php
header("Cache-Control: no-cache");
header("Content-Type: text/xml; charset=gb2312");
require("function.php");
$id = $_POST['id'];
$result = getResultById($id);
$xml = "<mes>";
foreach ($result as $row) {
$xml .= "<res><id>{$row['region_id']}</id><name>{$row['region_name']}</name></res>";
}
$xml .= "</mes>";
echo $xml;
?>
數據庫訪問層 (function.php)
<?php
function getResultById($id) {
$con = mysql_connect("localhost", "root", "");
if (!$con) return false;
// 關鍵:解決中文亂碼
$charset = "gb2312";
mysql_query("SET character_set_connection=$charset, character_set_results=$charset, character_set_client=binary");
mysql_select_db("ajax", $con);
$sql = "SELECT * FROM ecs_region WHERE parent_id = '$id'";
$res = mysql_query($sql);
$arr = [];
while ($row = mysql_fetch_assoc($res)) $arr[] = $row;
return $arr;
}
?>
現代化改造建議
- 前端改用
fetch + DOMParser 解析 XML,或直接協商 JSON 格式(application/json)簡化解析。
- 後端遷移至 PDO/MySQLi + Prepared Statements,防 SQL 注入。
- 編碼統一 UTF-8,避免 gb2312/UTF-8 混用導致的轉碼問題。
- 引入前端框架 管理狀態,組件化省市選擇器。