JS工厂模式实战:解决Token存储与跨域请求兼容
本文通过JavaScript工厂模式解决前端开发中的两个典型兼容性问题。针对Token存储,利用工厂根据浏览器是否支持H5返回LocalStorageUtil或CookieStorageUtil,实现平滑降级;针对IE8/9跨域限制,通过工厂创建XDomainRequest对象处理AJAX请求。代码通过统一接口write()和get()实现解耦,展示了设计模式在前端工程化中的实际价值。
一. 写在前面
工厂模式与抽象工厂在后台开发中已十分常见,其核心概念此处不再赘述。这些模式的主要作用是实现类与类、层与层之间的解耦。在JavaScript中,工厂模式的应用思想与后台一致,并无额外难点。本文将跳过理论介绍,直接展示具体的应用场景与代码实现。
前端开发中的兼容性问题场景
二. 场景描述
1. 近期项目采用Owin认证机制,因此需要妥善存储Token。由于API资源请求需在请求头的Authorization字段中携带Token以进行身份验证,为避免主流浏览器Cookie中重复存储Token导致的双重传输及冗余感,决定将Token存储于localStorage。然而,这带来了兼容性问题:不支持HTML5的旧版浏览器该如何处理?
2. 为实现前端资源全量部署至CDN(仅保留html、css、js),所有动态资源通过AJAX加载且涉及跨域。虽然现代浏览器解决跨域较为容易,但IE8和IE9默认关闭跨域功能,如何在此类浏览器中正常发起跨域请求?
三. 公共JS结构一览
通常,我会为应用定义一个全局的Application.js文件,其中包含核心逻辑。以下展示整体代码结构供参考:


基于工厂模式的解决方案实现
四. 引入工厂思想解决问题
针对上述两个兼容性问题,引入工厂模式。在工厂中根据浏览器类型创建不同的对象实例。
具体而言,在解决Token存储问题时,若浏览器支持HTML5,则使用localStorage存储;若不支持,则回退至Cookie存储。
由此衍生出两个JS对象:CookieStorageUtil和LocalStorageUtil。二者需实现相同的“接口”。此处未使用JS代码强制模拟接口,而是通过注释标注两个对象需实现相同的write()和get()方法。同时规范代码风格:以下划线开头的方法视为私有方法。这样在修改内部实现时,私有方法可随意调整,而对外暴露的方法名保持不变,这与后台面向接口编程的理念一致。需注意的是,JS无法通过function真正模拟类的私有方法,若外部调用下划线开头的私有方法导致后续修改影响功能,责任不在工厂封装本身。
具体代码实现如下:
/**
* Storage Factory -Author 吴双 cnblogs.com/tdws
*/
StorageUtilManager: new Object({
createStorageUtil: function () {
if (window.applicationCache) {
return AppUtil.LocalStorageUtil;
} else {
return AppUtil.CookieStorageUtil;
}
}
}),
/**
* implement Storage -Author 吴双
* write()
* get()
*/
CookieStorageUtil: {
write: function (key, dataObj) {
this._clearCookie(key);
//写入的字符串
var dataObjStr = JSON.stringify(dataObj);
this._setCookie(key, dataObjStr, 15);
},
get: function (key) {
return this._getCookie(key);
},
_setCookie: function (cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toUTCString();
var path = "path=/";
document.cookie = cname + "=" + cvalue + "; " + expires + "; " + path;
},
_getCookie: function (cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1);
if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
}
return null;
},
_clearCookie: function (key) {
this._setCookie(key, "", -1);
}
},
/**
* implement Storage cnblogs.com/tdws
* write()
* get()
*/
LocalStorageUtil: {
write: function (key, dataObj) {
this._writeLocalStorage(key, dataObj);
},
get: function (key) {
return this._getFromLocalStorage(key);
},
_writeLocalStorage: function (key, dataObj) {
var localStorage = window.localStorage;
localStorage.removeItem(key);
//对象转化为字符串,将objStr按正常的方式存入localStorage中
var dataObjStr = JSON.stringify(dataObj);
localStorage.setItem(key, dataObjStr);
},
_getFromLocalStorage: function (key) {
var localStorage = window.localStorage;
return localStorage.getItem(key);
},
_removeLocalStorage: function (key) {
var localStorage = window.localStorage;
localStorage.removeItem(key);
}
}
第二个问题同样通过工厂解决。在不支持跨域的浏览器中,工厂创建XDomainRequest对象来处理请求。两个HttpUtil对象依然实现相同的接口方法。针对跨域问题,推荐使用GitHub上Star数1.8k的jQuery插件:https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest。
此外,为避免工厂模式导致调用逻辑复杂化,我们对JS代码进行了简化处理。
AppUtil.currentHttpUtil = AppUtil.HttpUtilManager.createHttpUtil();
五. 写在最后
通过上述方式,问题得以平滑解决。StorageUtilManager作为工厂,使两个StorageUtil与调用方之间实现了有效解耦。或许有人会觉得“不过多了一个Manager”,但这正是设计模式的精髓——它是前人经验的总结,旨在更优雅地解决实际问题。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持本站!
JS合并多个数组的三种方法:concat、spread与flat
2026-11-05 17:39:45
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
