get参数过长的一种解决方案

时间:2022-08-26 08:18:45

答案是:sessionStorage

背景

有个需求是对资讯进行预览(类似于发博客前预览下效果这样),一种很容易想到的简单办法是将预览的内容(如标题和正文)通过get请求传递到预览页中,js代码如下:

function previewNews(){
var action = "XXXX" ;
// 拿到页面中的标题和正文
var title = $("#title").val();
var content = $("#content").val();

var url = action+ "?title=" + encodeURIComponent(title) + "&content=" + encodeURIComponent(content);
window.open(url);//打开拼接后的url
}

这种方法在标题和正文字数不多的情况下是没有问题的。but问题是,资讯的正文字数却经常出乎意料地很长。多长呢?长到预览页面load啊load啊就是load不出来。查了查,这是因为浏览器或者服务器对url有长度限制(很多人包括我自己误解为是HTTP get方法对参数的限制,其实不是)。百度来的资料如下:

Microsoft Internet Explorer (Browser)
IE浏览器对URL的最大限制为2083个字符,如果超过这个数字,提交按钮没有任何反应。
Firefox (Browser)
对于Firefox浏览器URL的长度限制为65,536个字符。
Safari (Browser)
URL最大长度限制为 80,000个字符。
Opera (Browser)
URL最大长度限制为190,000个字符。
Google (Browser)
URL最大长度限制为8182个字符。
Apache (Server)
能接受最大url长度为8,192个字符。
Microsoft Internet Information Server(IIS)
能接受最大url的长度为16,384个字符。

而且,中文是以urlencode后的编码形式进行传递。如果浏览器的编码为UTF8的话,一个汉字最终编码后的字符长度为9个字符。(这句话也是百度来的,未经证实)这么算算,对于IE浏览器来说,标题和正文加起来最多能输入231个中文,超过了就完蛋。那么通过get方式传递参数预览这样的解决办法就变得毫无用处,因为资讯一般来说至少是三五百字的,必须寻找替代方案。

替代方案

想到的两种替代方案如下:

  1. 将预览内容post到服务端,根据一个唯一标识生成缓存(有效时间5分钟),将唯一标识返回到前端,前端通过get方式传递唯一标识请求预览逻辑,拿到缓存的内容后渲染到页面。需要说明的是这里的缓存必须是分布式的。
  2. 通过H5的会话缓存sessionStorage将预览内容存储在浏览器,打开预览页后从sessionStorage中拿到内容就可以渲染出页面了。

第一个解决方案需要用到分布式缓存,而我们的应用目前还没有引入分布式缓存,为了一个预览功能引入分布式缓存无论从时间成本来说还是其他成本,都不划算。怎么算都是使用sessionStorage更加便捷。

走近sessionStorage

sessionStorage,顾名思义,是浏览器基于session的一种本地存储方式。这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage并不是一种持久化的本地存储。与之相对应的另一种H5本地存储技术localStorage却是一种持久化的本地存储方式。结合资讯预览的需求,明显sessionStorage更适用。虽然之前并没有用过sessionStorage,但我还是义无反顾地将它应用在了这个需求上。其实它的使用方法还算挺简单的:

function previewNews(){
var action = "XXX" ;

var newsId = $("#id").val();//资讯的唯一标识
var title = $("#title").val();
var content = $("#content").val();
//通过setItem方法存储value
sessionStorage.setItem(newsId+"_title",title);
sessionStorage.setItem(newsId+"_content",content);

var url = action+ "?newsId=" + newsId;
window.open(url);
}

预览页取内容时这样写:

$(document).ready(function() {
var newsId = $("#newsId").val();
//通过getItem方法获取value
var title = sessionStorage.getItem(newsId + "_title");
var content = sessionStorage.getItem(newsId + "_content");

$("#news_title").html(title);
$("news_content").html(content);
});

简单的几行代码,解决了因为内容过长不能预览的问题。但是别慌,还有一个潜在的问题需要解决,那就是,sessionStorage对IE的支持不够好。换句话说,如果用户使用的是IE浏览器,那么还是会打不开预览页。怎么办呢?不用慌,早已经有人帮我们解决好了,网上一搜就有了。简单说,如果是IE浏览器,那么我们引入一个js插件,这个插件用cookie重写了sessionStorage的几个方法(setItem、getItem等),代码一看便知:
插件名:sessionStorage.js

/**
*补充不支持sessionStorage的浏览器使用cookie代替
* 使用:
* sessionStorage.setItem("key","value");
* sessionStorage.getItem("key");
* */

if (!window.sessionStorage) {
window.sessionStorage = {
getItem: function(sKey) {
if (!sKey || !this.hasOwnProperty(sKey)) {
return null;
}
return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1"));
},
key: function(nKeyId) {
return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/, "").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId]);
},
setItem: function(sKey, sValue) {
if (!sKey) {
return;
}
document.cookie = escape(sKey) + "=" + escape(sValue) + "; path=/";
this.length = document.cookie.match(/\=/g).length;
},
length: 0,
removeItem: function(sKey) {
if (!sKey || !this.hasOwnProperty(sKey)) {
return;
}
document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
this.length--;
},
hasOwnProperty: function(sKey) {
return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
}
};
window.sessionStorage.length = (document.cookie.match(/\=/g) || window.sessionStorage).length;
}

将这个插件引入到用到sessionStorage的地方,就不怕IE不支持啦!