PHP存量系统信创迁移方法论与踩坑全解和 国产浏览器与PHP前端交互兼容性适配体系
·
两套体系完整讲透。全程大白话,所有代码可直接用,数据库/语法转换全部用官方自带工具(达梦 DTS、金仓
KDTS、Babel、PostCSS),不自研轮子。
---
第一部分:PHP 存量系统信创迁移方法论与踩坑全解
一、先搞懂"信创迁移"到底在迁什么
大白话:你原来的 PHP 系统跑在 Intel/AMD 的 x86 服务器 + CentOS + MySQL/Oracle + Apache/Nginx
上。信创就是把这一整套换成国产的:
┌────────────┬───────────────┬─────────────────────────────────────────────────────┐
│ 层级 │ 原来(海外) │ 信创(国产替换) │
├────────────┼───────────────┼─────────────────────────────────────────────────────┤
│ CPU │ Intel x86 │ 鲲鹏/飞腾(ARM64)、海光/兆芯(x86)、龙芯(LoongArch) │
├────────────┼───────────────┼─────────────────────────────────────────────────────┤
│ 操作系统 │ CentOS/RedHat │ 麒麟 Kylin V10、统信 UOS │
├────────────┼───────────────┼─────────────────────────────────────────────────────┤
│ 数据库 │ MySQL/Oracle │ 达梦 DM8、人大金仓 KingbaseES、OceanBase、openGauss │
├────────────┼───────────────┼─────────────────────────────────────────────────────┤
│ Web 中间件 │ Apache/Nginx │ 东方通 TongWeb、Nginx(国产编译版可继续用) │
├────────────┼───────────────┼─────────────────────────────────────────────────────┤
│ 浏览器 │ Chrome/Edge │ 奇安信、360、红莲花(都是 Chromium 内核) │
└────────────┴───────────────┴─────────────────────────────────────────────────────┘
最大的坑就一句话:CPU 从 x86 变成了 ARM64,字节序和指令集变了,PHP
本身没问题(开源能重编),但你装的那些扩展(swoole、redis、各种 .so)很多没有 ARM 版,要重新编译。
---
二、完整迁移流程(7 步法)
第1步 资产盘点 → 第2步 兼容性评估 → 第3步 环境搭建(ARM+国产OS)
→ 第4步 PHP及扩展重编译 → 第5步 数据库迁移(用官方工具)
→ 第6步 代码SQL方言改造 → 第7步 回归测试+性能压测
第 1 步:资产盘点(别上来就动手)
先把家底摸清楚。用这个脚本一次性扫出你系统依赖了什么:
#!/bin/bash
# 文件名你自己存,我这里只给代码:asset_scan.sh
# 作用:盘点 PHP 版本、所有扩展、用了哪些数据库函数、有没有写死 x86 的东西
echo "======== 1. PHP 版本 ========"
php -v
echo "======== 2. 已加载扩展(重点看哪些是第三方.so) ========"
php -m
echo "======== 3. 扩展物理文件位置(看有没有现成ARM版) ========"
php -i | grep extension_dir
ls -lh $(php -config --extension-dir 2>/dev/null || php -i | grep '^extension_dir' | awk '{print $3}')
echo "======== 4. 代码里用了哪些危险的数据库特有写法 ========"
# mysql_* 老函数(PHP7已删)、Oracle的OCI、SQL方言
grep -rn "mysql_query\|mysql_connect\|mysqli_\|oci_\|->query(" --include="*.php" . | head -50
echo "======== 5. 代码里有没有写死的本地命令/路径(ARM下可能没有) ========"
grep -rn "exec(\|shell_exec(\|system(\|/usr/bin/\|\.exe" --include="*.php" . | head -50
echo "======== 6. composer 依赖里有没有带C扩展的包 ========"
cat composer.json 2>/dev/null | grep -i "ext-"
盘点输出三张清单:
1. PHP 扩展清单(哪些要重编)
2. SQL 写法清单(哪些方言要改)
3. 系统调用清单(exec 调的命令 ARM 上有没有)
---
第 2 步:兼容性评估(判断哪些会爆雷)
按这个表自查,这是 90% 的坑所在:
┌────────────────────────────┬──────────────────────────────────────┬──────────────────────────────────────────┐
│ 风险点 │ 为什么会坑 │ 怎么处理 │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ swoole / swow │ 协程库深度依赖底层,早期版本没 ARM 包 │ 用 swoole 5.x+,官方已支持 ARM64,重编即可 │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ php-redis / mongodb 等 .so │ 二进制只编了 x86 │ 用 pecl install 在 ARM 机器上现编 │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ mysql_ 老函数* │ PHP7 已彻底删除 │ 全部换成 PDO(顺便为换库做准备) │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ Oracle OCI8 │ 达梦/金仓没有 OCI 接口 │ 换成 PDO,SQL 方言改造 │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ GD / ImageMagick │ 依赖系统图形库 │ 国产 OS 源里装 libpng/libjpeg 再编 │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ 写死的 /usr/bin/x86_64... │ ARM 路径不一样 │ 改成动态查找 which │
├────────────────────────────┼──────────────────────────────────────┼──────────────────────────────────────────┤
│ 整数/位运算依赖 32 位 │ LoongArch/ARM 都是 64 位 LP64 │ 一般无影响,但位掩码要 review │
└────────────────────────────┴──────────────────────────────────────┴──────────────────────────────────────────┘
---
第 3 步:搭建信创环境
以最主流的 麒麟 V10(ARM64)+ 达梦 DM8 为例。
# 看清楚架构,确认是 aarch64(ARM64)
uname -m # 输出 aarch64 就对了
cat /etc/os-release # 确认 Kylin V10
# 麒麟用的是自己的 yum 源,先装编译 PHP 必需的基础库
sudo yum install -y gcc gcc-c++ make autoconf \
libxml2-devel openssl-devel libcurl-devel \
libjpeg-turbo-devel libpng-devel freetype-devel \
oniguruma-devel sqlite-devel libzip-devel
---
第 4 步:PHP 及扩展重编译(核心)
大白话:PHP 源码是跨平台的,在 ARM 机器上重新 ./configure && make 就能编出 ARM 版,关键是扩展也得在 ARM 机器上现编。
# ===== 编译 PHP 8.3 本体(ARM64) =====
cd /usr/local/src
wget https://www.php.net/distributions/php-8.3.0.tar.gz
tar -zxvf php-8.3.0.tar.gz
cd php-8.3.0
# configure 不需要指定架构,编译器自动认 aarch64
./configure \
--prefix=/usr/local/php \
--with-config-file-path=/usr/local/php/etc \
--enable-fpm \
--with-openssl \
--with-curl \
--enable-mbstring \
--with-zlib \
--enable-gd --with-jpeg --with-freetype \
--with-pdo-mysql \
--enable-sockets \
--enable-opcache
make -j$(nproc) # nproc 自动用满核数
sudo make install
# ===== 用 pecl 现编扩展(它会自动针对 ARM 编) =====
sudo /usr/local/php/bin/pecl install redis
sudo /usr/local/php/bin/pecl install swoole # 5.x 已原生支持ARM
# 在 php.ini 里加上
echo "extension=redis.so" >> /usr/local/php/etc/php.ini
echo "extension=swoole.so" >> /usr/local/php/etc/php.ini
# 验证扩展真的是 ARM64 的
file /usr/local/php/lib/php/extensions/*/redis.so
# 输出里要有 "ARM aarch64" 字样才对
踩坑提醒:
- 别从 x86 机器拷 .so 过来,file 命令一查就是 x86-64,装上直接 segfault。
- swoole 一定用 5.x,4.x 老版本 ARM 下编译报错多。
---
第 5 步:数据库迁移(重点:全部用官方自带工具,不要手写脚本搬数据)
这是你特别强调的"用自带工具不自研"。各家国产库都有官方图形化迁移工具,直接把 MySQL/Oracle
的表结构+数据+索引一键搬过去。
方案 A:迁到达梦 DM8 ——用官方 DTS(DM Data Transfer Service)
达梦自带 dts 工具,在 达梦安装目录/tool/dts 下,图形界面操作:
1. 新建迁移 →选源(MySQL)→填 MySQL 连接
2. 选目标(DMSQL)→填达梦连接
3. 勾选要迁的表 →勾"迁移对象包含:表结构+数据+索引+约束"
4. 高级选项:把 "对象名大小写" 设为和原库一致(达梦默认大写,这是大坑!)
5. 点开始,它自动建表+灌数据
命令行批量方式(适合自动化):
# 达梦命令行迁移工具 dmfldr / dts_console
# 达梦提供 dts 的命令行版,导出一个迁移配置 xml 后执行
cd /opt/dmdbms/tool
./dts_console /file=migrate_config.xml /log=migrate.log
# migrate_config.xml 在图形界面里点"保存配置"就能生成,不用手写
方案 B:迁到人大金仓 KingbaseES ——用官方 KDTS + 实时同步用 KFS
# KDTS:全量迁移工具(金仓安装包自带,Tools/kdts 目录)
# 图形界面:配置源 MySQL →目标 Kingbase →自动转换数据类型 →迁移
# 它内置了 MySQL→Kingbase的类型映射,不用你自己对照
# KFS:迁移完之后,业务还在跑,用 KFS 做增量实时同步,实现"双跑不停机"
# 配置好后 MySQL 的新增改删会实时同步到 Kingbase,等切换窗口一到直接切
方案 C:迁到 OceanBase ——用官方 OMS(OceanBase Migration Service)
OMS 是图形化平台,功能最全:
- 结构迁移 + 全量迁移 + 增量同步 + 反向同步(回滚保险)
- MySQL 模式几乎零改造(OceanBase 高度兼容 MySQL 协议)
若你原库是 MySQL,迁 OceanBase 最省事,SQL 基本不用改。
选型大白话建议:
- 原来是 MySQL →优先 OceanBase(兼容 MySQL,代码几乎不改)。
- 政府/国企强制要求达梦/金仓 →用 达梦 DTS / 金仓 KDTS,但 SQL 方言要改(见第 6 步)。
- 原来是 Oracle →达梦兼容 Oracle 语法最好,用达梦,改动最小。
---
第 6 步:代码 SQL 方言改造(改造量最大的一步)
大白话:不同数据库 SQL 写法有差异,达梦/金仓不认 MySQL 的某些语法。最优策略——用PDO
把数据库访问收口到一个地方,改一处就行,别在几百个文件里散着写 SQL。
6.1 先把所有数据库访问统一成 PDO(标准做法,最优方案)
<?php
// 统一数据库连接层 ——改库只改这一个文件的 DSN
class Db
{
private static ?PDO $pdo = null;
public static function conn(): PDO
{
if (self::$pdo !== null) {
return self::$pdo;
}
// ===== 切换数据库就改这里的 DSN,业务代码一行不动 =====
// 原 MySQL:
// $dsn = 'mysql:host=127.0.0.1;port=3306;dbname=app;charset=utf8mb4';
// 达梦 DM8(走官方 PDO_DM 驱动 或 ODBC):
// $dsn = 'dm:host=127.0.0.1;port=5236';
// 人大金仓 / openGauss(兼容 PostgreSQL 协议,用 pdo_pgsql):
// $dsn = 'pgsql:host=127.0.0.1;port=54321;dbname=app';
// OceanBase(兼容 MySQL,继续用 pdo_mysql):
$dsn = 'mysql:host=127.0.0.1;port=2883;dbname=app;charset=utf8mb4';
self::$pdo = new PDO($dsn, 'username', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 用真预处理,防注入也更兼容
]);
return self::$pdo;
}
}
业务里全部用预处理,杜绝 SQL 注入,也最容易跨库:
<?php
// 所有查询都走这个标准姿势
$stmt = Db::conn()->prepare('SELECT id, name FROM users WHERE age > ? AND city = ?');
$stmt->execute([18, '北京']);
$rows = $stmt->fetchAll();
6.2 常见 SQL 方言差异对照表(达梦/金仓踩坑清单)
┌──────────────────────────────────┬─────────────────────────────────┬───────────────────────────────────────────┐
│ MySQL 写法 │ 达梦 / 金仓 不认 │ 跨库正确写法 │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ `column` 反引号 │ 不支持反引号 │ 用双引号 "column" 或不加引号 │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ LIMIT 10 OFFSET 20 │ 达梦用 │ 用标准 OFFSET 20 ROWS FETCH NEXT 10 ROWS │
│ │ LIMIT,金仓支持但语法略不同 │ ONLY │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ IFNULL(a,b) │ 不支持 │ 用标准 COALESCE(a,b) │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ NOW() / CURDATE() │ 部分不支持 │ 达梦用 SYSDATE,金仓用 CURRENT_TIMESTAMP │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ GROUP_CONCAT() │ 不支持 │ 达梦 WM_CONCAT,金仓 STRING_AGG │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ INSERT ... ON DUPLICATE KEY │ 不支持 │ 用标准 MERGE INTO │
│ UPDATE │ │ │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ auto_increment │ 写法不同 │ 达梦/金仓用序列 SEQUENCE │
├──────────────────────────────────┼─────────────────────────────────┼───────────────────────────────────────────┤
│ 表名/字段名大小写不敏感 │ 达梦默认全大写 │ 迁移时统一,或代码里全大写 │
└──────────────────────────────────┴─────────────────────────────────┴───────────────────────────────────────────┘
最优做法:用查询构造器 / ORM 屏蔽方言,别手写裸 SQL。 推荐用 Laravel 的 Eloquent / 查询构造器 或 Doctrine DBAL,它们内置
了各数据库的"语法转换器(Grammar)",你写一份代码,它自动翻译成对应数据库的方言——这就是你要的"用自带语法转换工具不自研":
<?php
// 用 Laravel 查询构造器,跨库零改造(它内部按驱动自动生成对应方言SQL)
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
'driver' => 'pgsql', // 金仓/openGauss 用 pgsql;OceanBase 用 mysql;达梦用社区dm驱动
'host' => '127.0.0.1',
'port' => '54321',
'database' => 'app',
'username' => 'user',
'password' => 'pwd',
]);
$capsule->setAsGlobal();
$capsule->bootEloquent();
// 业务代码完全不感知底层是什么库,框架自动翻译方言
$users = Capsule::table('users')
->where('age', '>', 18)
->orderBy('id')
->limit(10)->offset(20) // 框架自动转成各库正确的分页语法
->get();
---
第 7 步:回归测试 + 性能压测
# 1. 功能回归:跑你原有的 PHPUnit 测试套件
./vendor/bin/phpunit
# 2. 接口回归:用 ab 压测对比 x86 和 ARM 下的接口表现
ab -n 5000 -c 100 http://127.0.0.1/api/users
# 3. 重点压数据库:达梦/金仓的执行计划和 MySQL 不同,慢SQL要重新优化
# 达梦看执行计划:
# EXPLAIN SELECT ... ; 然后对慢查询补索引
ARM 性能踩坑: ARM 单核主频可能低于 Intel,但核多。PHP-FPM 的 pm.max_children 要按 ARM 核数调大,把多核吃满,整体吞吐不输
x86。
---
三、PHP 信创迁移踩坑 Top 10 速查
1. 从 x86 拷 .so 到 ARM →必崩,所有扩展 ARM 机现编。
2. 达梦默认大写表名 →迁移和代码大小写不一致,查不到数据。迁移时统一。
3. mysql_ 老函数* →PHP7+ 已删,全换 PDO。
4. 反引号 ` →达梦/金仓不认,换双引号。
5. 自增主键 →国产库要建 SEQUENCE,迁移工具能自动转,别手建漏了。
6. 中文乱码 →字符集统一 UTF-8,达梦建库时指定 CHARSET=UTF-8。
7. swoole 4.x →ARM 编译报错,升 5.x。
8. exec 调系统命令 →ARM 上命令路径/参数不同,用 which 动态找。
9. 时间函数 NOW()/SYSDATE →方言不同,用 ORM 或 COALESCE 类标准函数。
10. 不做增量同步直接停机切 →数据丢失风险,用 KFS/OMS 做双跑同步再切。
---
---
第二部分:国产浏览器与 PHP 前端交互兼容性适配体系
一、先搞懂国产浏览器到底是什么
大白话:国产浏览器(奇安信、360 安全浏览器、红莲花、UOS 浏览器)绝大多数是基于 Chromium 内核改的,所以现代 JS/CSS
基本都支持。真正的坑是两个:
1. 双核浏览器:360、搜狗这类有"极速模式(Chromium)"和"兼容模式(IE 内核 Trident)"两套内核。政府老系统常被强制用 IE
兼容模式,那就是 IE8/IE9 级别的远古环境,你的 ES6、fetch、flex 全跪。
2. Chromium 版本偏老:有些国产浏览器内核停留在 Chromium 8x、9x,最新的 ES2022 语法、?. 可选链可能不支持。
核心策略一句话:用 Babel 把新 JS 翻译成老 JS,用 PostCSS+Autoprefixer 把新 CSS 翻译成老 CSS,用 core-js 把缺失的 API
补上。这些全是业界标准工具,绝不自研。
---
二、完整适配流程
第1步 探测目标浏览器内核与版本 → 第2步 定 browserslist 目标
→ 第3步 Babel转译JS+core-js补丁 → 第4步 PostCSS转译CSS
→ 第5步 PHP后端按UA下发对应资源 → 第6步 IE兼容模式兜底处理
→ 第7步 真机回归测试
---
第 1 步:探测目标浏览器(先知道敌人是谁)
后端用 PHP 解析 UA,前端用 JS 探测能力。先做个探测页跑一遍:
<?php
// 后端探测:解析 User-Agent,判断是哪个国产浏览器、什么内核
function detectBrowser(string $ua): array
{
$result = ['name' => 'unknown', 'engine' => 'unknown', 'mode' => 'modern'];
// 国产浏览器特征(它们 UA 里都带各自标识)
if (stripos($ua, 'QihooBrowser') !== false || stripos($ua, 'QiHoo') !== false) {
$result['name'] = '奇安信/360';
} elseif (stripos($ua, 'UOSBrowser') !== false) {
$result['name'] = '统信UOS浏览器';
} elseif (stripos($ua, 'Hongmeng') !== false || stripos($ua, 'HarmonyOS') !== false) {
$result['name'] = '鸿蒙';
}
// 关键:判断是不是落到了 IE 兼容模式(Trident=IE内核)
if (stripos($ua, 'Trident') !== false || stripos($ua, 'MSIE') !== false) {
$result['engine'] = 'Trident(IE内核)';
$result['mode'] = 'legacy'; // 远古模式,要兜底!
} elseif (stripos($ua, 'Chrome') !== false) {
// 抓出 Chromium 版本号,判断老不老
preg_match('/Chrome\/(\d+)/', $ua, $m);
$ver = (int)($m[1] ?? 0);
$result['engine'] = "Chromium $ver";
$result['mode'] = $ver < 80 ? 'old-chromium' : 'modern';
}
return $result;
}
// 用法
$info = detectBrowser($_SERVER['HTTP_USER_AGENT'] ?? '');
// $info['mode'] 决定后面下发哪套前端资源
---
第 2 步:用 browserslist 声明你要兼容到多老
大白话:browserslist 是一个配置文件,你写明"我要支持到 IE9、Chrome
49",后面所有工具(Babel、PostCSS)都读它,自动决定翻译到什么程度。这是整个体系的总开关。
// package.json 里加一段(这就是 browserslist 配置,业界标准,所有工具都认它)
{
"browserslist": [
"> 0.5%",
"last 2 versions",
"Chrome >= 49",
"ie >= 9",
"Firefox ESR"
]
}
如果确认要兼容 IE 兼容模式(政府场景),就把 ie >= 9 写进去,Babel 会自动转到 ES5。
---
第 3 步:Babel 转译 JS + core-js 补 API(最关键)
大白话:你写 ES6+ 的现代 JS(箭头函数、const、async/await、可选链),Babel 自动翻译成老浏览器能跑的 ES5。语法它翻译,新
API(Promise、fetch、Array.includes)它用 core-js 补丁补上。全自动,你只管写现代代码。
# 安装 Babel 全家桶 + core-js(都是官方标准库,不自研)
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install core-js@3
// babel.config.js ——Babel 配置,核心是 preset-env + corejs
module.exports = {
presets: [
['@babel/preset-env', {
// 不写 targets,它自动读 package.json 里的 browserslist
useBuiltIns: 'usage', // 关键:只按你代码实际用到的API来打补丁,体积最小
corejs: 3, // 用 core-js@3 提供 Promise/fetch等垫片
}],
],
};
# 执行转译:把现代源码 src/ 翻译成老浏览器能跑的 dist/
npx babel src --out-dir dist
效果对比(Babel 自动帮你做的翻译):
// 你写的现代代码(src/app.js)
const getUser = async (id) => {
const res = await fetch(`/api/user?id=${id}`);
const data = await res.json();
return data?.name ?? '匿名'; // 可选链 + 空值合并
};
// Babel 自动翻译成 ES5(dist/app.js),IE 也能跑(配合core-js的Promise/fetch补丁)
// 你完全不用手写这些兼容代码,Babel 全自动生成
踩坑提醒: 一定要装 core-js 并设 useBuiltIns: 'usage'。光转语法不补 API,IE 里 Promise is not defined 照样崩。
---
第 4 步:PostCSS 转译 CSS + Autoprefixer 自动加前缀
大白话:CSS 也一样。你写标准的 flex、grid,Autoprefixer 自动加 -webkit-、-ms- 前缀让老内核认识。同样读
browserslist,全自动。
npm install --save-dev postcss postcss-cli autoprefixer postcss-preset-env
// postcss.config.js
module.exports = {
plugins: [
// postcss-preset-env:把现代CSS(嵌套、自定义属性)翻译成老CSS
require('postcss-preset-env')({ stage: 2 }),
// autoprefixer:自动加浏览器前缀,也是读 browserslist
require('autoprefixer'),
],
};
npx postcss src/style.css -o dist/style.css
效果:
/* 你写的现代 CSS */
.box { display: flex; user-select: none; }
/* Autoprefixer 自动加前缀后(老国产内核/IE兼容模式能认) */
.box {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
最优整合方案:别手动跑 babel/postcss 命令,用 Vite 打包,它内部集成了这一整套。
// vite.config.js ——最优:一个配置全搞定,生产构建自动 Babel+PostCSS+legacy 兜底
import { defineConfig } from 'vite';
import legacy from '@vitejs/plugin-legacy';
export default defineConfig({
plugins: [
// 这个官方插件自动为老浏览器生成 ES5 版本 + 注入 polyfill,IE11也能跑
legacy({
targets: ['ie >= 11', 'Chrome >= 49'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
}),
],
});
@vitejs/plugin-legacy 是最省事的——它会自动产出现代版和老旧版两套bundle,现代浏览器加载现代版,老国产浏览器自动降级加载
ES5 版,完全自动。
---
第 5 步:PHP 后端按浏览器下发对应资源(差异化下发)
大白话:用第 1 步探测的结果,给现代浏览器发现代 bundle,给 IE 兼容模式发 ES5 兜底版。这叫"自适应下发"。
<?php
// PHP 模板里,根据探测结果决定加载哪套前端资源
$info = detectBrowser($_SERVER['HTTP_USER_AGENT'] ?? '');
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- 关键!强制 360/搜狗双核浏览器用"极速模式(Chromium)"而不是IE兼容模式 -->
<meta name="renderer" content="webkit">
<!-- 强制 IE 用最高级内核,别用兼容视图 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<?php if ($info['mode'] === 'legacy'): ?>
<!-- 落到IE内核了:加载 ES5 兜底版 + 提示升级 -->
<script nomodule src="/dist/legacy/app.es5.js"></script>
<link rel="stylesheet" href="/dist/legacy/style.css">
<?php else: ?>
<!-- 现代内核:加载现代版,用 type=module 让老浏览器自动忽略 -->
<script type="module" src="/dist/modern/app.js"></script>
<link rel="stylesheet" href="/dist/modern/style.css">
<?php endif; ?>
</head>
<body>
<div id="app"></div>
</body>
</html>
<meta name="renderer" content="webkit"> 这行是国产双核浏览器的命脉——它告诉360/搜狗:"用 Chromium 极速内核渲染我,别用
IE 兼容内核"。加了这行,90% 的国产浏览器兼容问题直接消失。
---
第 6 步:IE 兼容模式兜底(实在躲不掉的远古环境)
如果客户死活要求在 IE 兼容模式下能用,加这层兜底:
<!-- 在 <head> 最前面用条件注释引入IE专用polyfill(只有IE认条件注释) -->
<!--[if lte IE 9]>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,fetch,Promise"></script>
<![endif]-->
// 前端能力探测降级:发现是远古环境就给个友好提示,引导用极速模式
if (!window.fetch || !window.Promise) {
document.getElementById('app').innerHTML =
'<div style="padding:40px;text-align:center;">' +
'检测到您正在使用兼容(IE)模式,请点击地址栏右侧的<b>闪电图标</b>切换到"极速模式"以获得最佳体验。' +
'</div>';
}
---
第 7 步:真机回归测试
大白话:国产浏览器有自己的怪癖,模拟器不准,必须真机测。 重点测这几样:
// 兼容性自检脚本,在目标国产浏览器里跑一遍,看哪些挂了
const checks = {
'ES6箭头函数': (() => { try { eval('(()=>{})'); return true; } catch { return false; } })(),
'Promise': typeof Promise !== 'undefined',
'fetch': typeof fetch !== 'undefined',
'Flexbox': CSS.supports && CSS.supports('display', 'flex'),
'Grid': CSS.supports && CSS.supports('display', 'grid'),
'CSS变量': CSS.supports && CSS.supports('--a', '0'),
};
console.table(checks); // 哪个是 false 就针对性补 polyfill
测试矩阵建议覆盖:奇安信浏览器、360(极速+兼容双模式)、统信 UOS 浏览器、红莲花 ×麒麟/UOS 操作系统。
---
三、前端兼容踩坑 Top 8 速查
1. 双核浏览器默认进了 IE 兼容模式 →加 <meta name="renderer" content="webkit"> 强制极速内核。
2. 只转语法没补 API →装 core-js,Promise is not defined 才不会崩。
3. 手写兼容代码 →别!用 Babel+Autoprefixer 自动转,自研必出错。
4. 国产浏览器 Chromium 版本偏老 →browserslist 里目标定低一点,如 Chrome >= 49。
5. 字体问题 →国产 OS 默认无微软雅黑,CSS 里 font-family 加 "思源黑体","Noto Sans CJK" 兜底。
6. HTTPS 国密证书 →国产浏览器可能要求 SM2 国密证书,Nginx 要配国密版。
7. <meta charset> 没写或写晚 →中文乱码,必须放 <head> 第一行。
8. fetch 跨域 →老国产内核 CORS 实现有差异,后端 PHP 记得发全 Access-Control-Allow-* 头。
---
四、两套体系的"最优工具链"总结
┌─────────────────┬─────────────────────────────────────────────────────┐
│ 任务 │ 最优工具(全是官方/业界标准,不自研) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ MySQL→达梦迁移 │ 达梦官方 DTS │
├─────────────────┼─────────────────────────────────────────────────────┤
│ MySQL→金仓迁移 │ 金仓 KDTS(全量)+ KFS(增量同步) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ MySQL→OceanBase│ OMS 迁移服务(最省事) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ Oracle→国产库 │ 达梦(Oracle 兼容最好) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ PHP 数据库跨库 │ PDO + Laravel查询构造器/Doctrine DBAL(自动方言转换) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ PHP 扩展 ARM 化 │ pecl 现编(不要拷贝 .so) │
├─────────────────┼─────────────────────────────────────────────────────┤
│ JS 语法转译 │ Babel @babel/preset-env │
├─────────────────┼─────────────────────────────────────────────────────┤
│ JS API 补丁 │ core-js@3 │
├─────────────────┼─────────────────────────────────────────────────────┤
│ CSS 转译加前缀 │ PostCSS + Autoprefixer + postcss-preset-env │
├─────────────────┼─────────────────────────────────────────────────────┤
│ 一键打包+降级 │ Vite + @vitejs/plugin-legacy │
└─────────────────┴─────────────────────────────────────────────────────┘
---
需要我针对你的具体场景再往下钻吗?比如:
- 你现在用的是 MySQL 还是 Oracle,目标是 达梦还是金仓?我给你专门那条线的完整迁移脚本。
- 你的 PHP 框架是 Laravel / ThinkPHP / 原生?改造方式不一样,我给对应的改法。
- 国产浏览器具体是哪几款?我帮你定精确的 browserslist。
告诉我环境,我直接给你贴合实际的完整代码。
更多推荐


所有评论(0)