一般我们启动gzip都比较少对html启动gzip,因为现在的html都是动态的,不会使用浏览器缓存,而启用gzip的话每次请求都需要压缩,会比较消耗服务器资源,对js,css启动gzip比较好是因为js,css都会使用缓存。我个人觉得的压缩html的最大好处就是一本万利,只要写好了一次,以后所有程序都可以使用,不会增加任何额外的开发工作。
在“JS、CSS的合并、压缩、缓存管理”一文中说到自己写过的1个自动合并、压缩JS,CSS,并添加版本号的组件。这次把压缩html的功能也加入到该组件中,流程很简单,就是在程序启动(contextInitialized or Application_Start)的时候扫描所有html,jsp(aspx)进行压缩。
压缩的注意事项:
实现的方式主要是用正则表达式去查找,替换。在html压缩的时候,主要要注意下面几点:
1. pre,textarea 标签里面的内容格式需要保留,不能压缩。
2. 去掉html注释的时候,有些注释是不能去掉的,比如:<!--[if IE 6]> ..... <![endif]-->
3. 压缩嵌入式js中的注释要注意,因为可能注释符号会出现在字符串中,比如: var url = "http://www.cnblogs.com"; // 前面的//不是注释
去掉JS换行符的时候,不能直接跟一下行动内容,需要有空格,考虑下面的代码:
else
return;
如果不带空格,则变成elsereturn。
4. jsp(aspx) 中很有可能会使用<% %>嵌入一些服务器代码,这个时候也需要单独处理,里面注释的处理方法跟js的一样。
源代码:
下面是java实现的源代码,也可以 猛击此处 下载该代码,相信大家都看的懂,也很容易改成net代码:
复制代码 代码如下:
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;
import java.util.regex.*;
/*******************************************
* 压缩jsp,html中的代码,去掉所有空白符、换行符
* @author bearrui(ak-47)
* @version 0.1
* @date 2010-5-13
*******************************************/
public class HtmlCompressor {
private static String tempPreBlock = "%%%HTMLCOMPRESS~PRE&&&";
private static String tempTextAreaBlock = "%%%HTMLCOMPRESS~TEXTAREA&&&";
private static String tempScriptBlock = "%%%HTMLCOMPRESS~SCRIPT&&&";
private static String tempStyleBlock = "%%%HTMLCOMPRESS~STYLE&&&";
private static String tempJspBlock = "%%%HTMLCOMPRESS~JSP&&&";
private static Pattern commentPattern = Pattern.compile("<!--\\s*[^\\[].*?-->", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static Pattern itsPattern = Pattern.compile(">\\s+?<", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static Pattern prePattern = Pattern.compile("<pre[^>]*?>.*?</pre>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static Pattern taPattern = Pattern.compile("<textarea[^>]*?>.*?</textarea>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static Pattern jspPattern = Pattern.compile("<%([^-@][\\w\\W]*?)%>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
// <script></script>
private static Pattern scriptPattern = Pattern.compile("(?:<script\\s*>|<script type=['\"]text/javascript['\"]\\s*>)(.*?)</script>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static Pattern stylePattern = Pattern.compile("<style[^>()]*?>(.+)</style>", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
// 单行注释,
private static Pattern signleCommentPattern = Pattern.compile("//.*");
// 字符串匹配
private static Pattern stringPattern = Pattern.compile("(\"[^\"\\n]*?\"|'[^'\\n]*?')");
// trim去空格和换行符
private static Pattern trimPattern = Pattern.compile("\\n\\s*",Pattern.MULTILINE);
private static Pattern trimPattern2 = Pattern.compile("\\s*\\r",Pattern.MULTILINE);
// 多行注释
private static Pattern multiCommentPattern = Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
private static String tempSingleCommentBlock = "%%%HTMLCOMPRESS~SINGLECOMMENT&&&"; // //占位符
private static String tempMulitCommentBlock1 = "%%%HTMLCOMPRESS~MULITCOMMENT1&&&"; // /*占位符
private static String tempMulitCommentBlock2 = "%%%HTMLCOMPRESS~MULITCOMMENT2&&&"; // */占位符
public static String compress(String html) throws Exception {
if(html == null || html.length() == 0) {
return html;
}
List<String> preBlocks = new ArrayList<String>();
List<String> taBlocks = new ArrayList<String>();
List<String> scriptBlocks = new ArrayList<String>();
List<String> styleBlocks = new ArrayList<String>();
List<String> jspBlocks = new ArrayList<String>();
String result = html;
//preserve inline java code
Matcher jspMatcher = jspPattern.matcher(result);
while(jspMatcher.find()) {
jspBlocks.add(jspMatcher.group(0));
}
result = jspMatcher.replaceAll(tempJspBlock);
//preserve PRE tags
Matcher preMatcher = prePattern.matcher(result);
while(preMatcher.find()) {
preBlocks.add(preMatcher.group(0));
}
result = preMatcher.replaceAll(tempPreBlock);
//preserve TEXTAREA tags
Matcher taMatcher = taPattern.matcher(result);
while(taMatcher.find()) {
taBlocks.add(taMatcher.group(0));
}
result = taMatcher.replaceAll(tempTextAreaBlock);
//preserve SCRIPT tags
Matcher scriptMatcher = scriptPattern.matcher(result);
while(scriptMatcher.find()) {
scriptBlocks.add(scriptMatcher.group(0));
}
result = scriptMatcher.replaceAll(tempScriptBlock);
// don't process inline css
Matcher styleMatcher = stylePattern.matcher(result);
while(styleMatcher.find()) {
styleBlocks.add(styleMatcher.group(0));
}
result = styleMatcher.replaceAll(tempStyleBlock);
//process pure html
result = processHtml(result);
//process preserved blocks
result = processPreBlocks(result, preBlocks);
result = processTextareaBlocks(result, taBlocks);
result = processScriptBlocks(result, scriptBlocks);
result = processStyleBlocks(result, styleBlocks);
result = processJspBlocks(result, jspBlocks);
preBlocks = taBlocks = scriptBlocks = styleBlocks = jspBlocks = null;
return result.trim();
}
private static String processHtml(String html) {
String result = html;
//remove comments
// if(removeComments) {
result = commentPattern.matcher(result).replaceAll("");
// }
//remove inter-tag spaces
// if(removeIntertagSpaces) {
result = itsPattern.matcher(result).replaceAll("><");
// }
//remove multi whitespace characters
// if(removeMultiSpaces) {
result = result.replaceAll("\\s{2,}"," ");
// }
return result;
}
private static String processJspBlocks(String html, List<String> blocks){
String result = html;
for(int i = 0; i < blocks.size(); i++) {
blocks.set(i, compressJsp(blocks.get(i)));
}
//put preserved blocks back
while(result.contains(tempJspBlock)) {
result = result.replaceFirst(tempJspBlock, Matcher.quoteReplacement(blocks.remove(0)));
}
return result;
}
private static String processPreBlocks(String html, List<String> blocks) throws Exception {
String result = html;
//put preserved blocks back
while(result.contains(tempPreBlock)) {
result = result.replaceFirst(tempPreBlock, Matcher.quoteReplacement(blocks.remove(0)));
}
return result;
}
private static String processTextareaBlocks(String html, List<String> blocks) throws Exception {
String result = html;
//put preserved blocks back
while(result.contains(tempTextAreaBlock)) {
result = result.replaceFirst(tempTextAreaBlock, Matcher.quoteReplacement(blocks.remove(0)));
}
return result;
}
private static String processScriptBlocks(String html, List<String> blocks) throws Exception {
String result = html;
// if(compressJavaScript) {
for(int i = 0; i < blocks.size(); i++) {
blocks.set(i, compressJavaScript(blocks.get(i)));
}
// }
//put preserved blocks back
while(result.contains(tempScriptBlock)) {
result = result.replaceFirst(tempScriptBlock, Matcher.quoteReplacement(blocks.remove(0)));
}
return result;
}
private static String processStyleBlocks(String html, List<String> blocks) throws Exception {
String result = html;
// if(compressCss) {
for(int i = 0; i < blocks.size(); i++) {
blocks.set(i, compressCssStyles(blocks.get(i)));
}
// }
//put preserved blocks back
while(result.contains(tempStyleBlock)) {
result = result.replaceFirst(tempStyleBlock, Matcher.quoteReplacement(blocks.remove(0)));
}
return result;
}
private static String compressJsp(String source) {
//check if block is not empty
Matcher jspMatcher = jspPattern.matcher(source);
if(jspMatcher.find()) {
String result = compressJspJs(jspMatcher.group(1));
return (new StringBuilder(source.substring(0, jspMatcher.start(1))).append(result).append(source.substring(jspMatcher.end(1)))).toString();
} else {
return source;
}
}
private static String compressJavaScript(String source) {
//check if block is not empty
Matcher scriptMatcher = scriptPattern.matcher(source);
if(scriptMatcher.find()) {
String result = compressJspJs(scriptMatcher.group(1));
return (new StringBuilder(source.substring(0, scriptMatcher.start(1))).append(result).append(source.substring(scriptMatcher.end(1)))).toString();
} else {
return source;
}
}
private static String compressCssStyles(String source) {
//check if block is not empty
Matcher styleMatcher = stylePattern.matcher(source);
if(styleMatcher.find()) {
// 去掉注释,换行
String result= multiCommentPattern.matcher(styleMatcher.group(1)).replaceAll("");
result = trimPattern.matcher(result).replaceAll("");
result = trimPattern2.matcher(result).replaceAll("");
return (new StringBuilder(source.substring(0, styleMatcher.start(1))).append(result).append(source.substring(styleMatcher.end(1)))).toString();
} else {
return source;
}
}
private static String compressJspJs(String source){
String result = source;
// 因注释符合有可能出现在字符串中,所以要先把字符串中的特殊符好去掉
Matcher stringMatcher = stringPattern.matcher(result);
while(stringMatcher.find()){
String tmpStr = stringMatcher.group(0);
if(tmpStr.indexOf("//") != -1 || tmpStr.indexOf("/*") != -1 || tmpStr.indexOf("*/") != -1){
String blockStr = tmpStr.replaceAll("//", tempSingleCommentBlock).replaceAll("/\\*", tempMulitCommentBlock1)
.replaceAll("\\*/", tempMulitCommentBlock2);
result = result.replace(tmpStr, blockStr);
}
}
// 去掉注释
result = signleCommentPattern.matcher(result).replaceAll("");
result = multiCommentPattern.matcher(result).replaceAll("");
result = trimPattern2.matcher(result).replaceAll("");
result = trimPattern.matcher(result).replaceAll(" ");
// 恢复替换掉的字符串
result = result.replaceAll(tempSingleCommentBlock, "//").replaceAll(tempMulitCommentBlock1, "/*")
.replaceAll(tempMulitCommentBlock2, "*/");
return result;
}
}
使用注意事项:
使用了上面方法后,再运行程序,是不是发现每个页面查看源代码的时候都变成1行啦,还不错吧,但是在使用的时候还是要注意一些问题:
1. 嵌入js本来想调用yuicompressor来压缩,yuicompressor压缩JS前,会先编译js是否合法,因我们嵌入的js中可能很多会用到一些服务器端代码,比如 var now = <%=DateTime.now %> ,这样的代码会编译不通过,所以无法使用yuicompressor。
最后只能自己写压缩JS代码,自己写的比较粗燥,所以有个问题还解决,就是如果开发人员在一句js代码后面没有加分号的话,压缩成1行就很有可能出问题。所以使用这个需要保证每条语句结束后都必须带分号。
2. 因为是在程序启动的时候压缩所有jsp(aspx),所以如果是用户请求的时候动态产生的html就无法压缩。
相关推荐:
seo灰帽是什么,灰帽是指什么 ,ai绘画六边形
SEO汇报:如何通过数据分析提升网站排名,助力企业业绩增长,免费推广网站大全百度经验
为什么关键词太少会影响你的网络营销效果?,陕西seo网站推广工具
SEO外链技巧:提升网站排名的秘密武器,ai视频生日祝福
SEO优化做什么的?揭秘SEO优化的核心价值与实战应用,ai做金色
ChatGPT页面空白不乏登录:让你秒变职场高手与生活智囊,百度ai 腾讯ai
用AI写的文章算原创吗?真相揭示,带你深度思考!
ChatGPT360:全方位提升你的工作与生活效率,ai72787
SEO关键词是什么意思?全面解析SEO关键字的核心作用,华为ai音箱 百度ai音箱
SEO优:让网站流量和排名实现飞跃的秘诀,大理哪有企业网站建设
seo追词是什么,seo词条 ,52580609AI
seo网页优化什么意思,seo网站优化必知的10个问答,问吧,【解决】百度不知道 ,ai识别点读机
丹东seo是什么怎么选,丹东spr ,黑发ai图
ChatGPT连了外网也登不了?如何解决这一问题,重新畅享AI助力!,ai少女大瓜
AI写作技巧,让创作事半功倍!
SEO优化快:如何在短时间内实现网站流量爆发,Lacey0508ai
ChatGLM不能搜索网页内容,你真的了解它的局限性吗?,ai修复情侣
SEO实现:如何通过SEO优化提升网站流量与排名,南京市公司网站推广
AI批量文章工具,让写作变得高效与轻松,cs机器人ai
如何利用AI生成高质量文章,提升写作效率与创意?
AI缩短短文-提升创作效率,写作新体验,光速写作业ai写作app
什么是seo手段,seo的具体手段 ,中国ai 企业
ChatGPT与讯飞:AI语音与智能对话的完美融合,ai直角变圆角
SEO超级,助力企业站点冲刺搜索引擎排名,白云全网营销推广哪家强
SEO与网络推广机构:如何选择最适合你的数字营销合作伙伴,ai写作软件性价比高吗
SEO添加:提升网站流量与排名的必备策略,seo团队成员中国人
SEO未来:如何在变革中抢占先机,迎接数字营销的新纪元,台州网站建设分析和总结
seo营销到底是什么,seo算什么营销 ,ai里面新建
亚马逊站内seo是什么优化,亚马逊seo关键词优化软件 ,ai画卡通章鱼
为什么seo这么难,seo难嘛 ,ai宁中则
SEO考核:如何通过精准的SEO优化提升网站排名与流量,茶艺营销推广方案怎么写
SEO埋词技巧,如何提升网站排名?,贵州营销推广方法
什么是seo行业,seo是什么职业做什么的 ,ai标题字体效果
AI搜索写文章是什么意思?人工智能赋能内容创作的未来,高德地图 ai
Zkept:重塑未来生活的智能科技革新,营销推广的面试问题
ChatGPT当前不可用?如何应对AI服务中断的挑战,ai文章免费写作app
seo网站关键字排名优化,网站seo关键词 ,运动ai
seo用什么论坛引流,seo引流方法 ,ai写作续写神器
pbootcms自动翻译插件,让你的网站轻松实现多语言覆盖,ai 镀金
怎么用AI生成文章?全新写作方式的揭秘与应用指南
seo组建需要什么条件,seo建站的步骤 ,ai肌肉宝宝
ChatGPT服务部分恢复:人工智能助力全新体验,ai对象菜单
怎么用AI生成文章免费版,高效创作从此开始!
SEO可以改变你的商业未来:如何通过优化提升网站流量和转化率,五粮液营销推广
为什么“360收录”是你网站推广的必备利器,seo亚马逊
AI文章精简-高效提炼与优化你的内容创作,ai quid
SEO技巧提升网站流量和排名,助力企业快速崛起,ai080206.
为什么做酒店seo,为什么做酒店 ,ai uehara下载
SEO动态:2025年SEO趋势与优化技巧解析,十堰外贸网站推广费用
怎么分辨文章是不是AI写的?五大技巧揭开真相