记一次Css样式var()函数替换失败的排查过程和原因分析(服务器GZIP压缩导致出错)

5 篇文章 0 订阅
1 篇文章 0 订阅

前几天客户现场国产服务器部署应用时,出现了和weblogic服务器表现不一致的地方,案列很简单:就是样式在加载过程中使用了css的var() 函数。而导致后面css样式加载失败失败,var定义的值没有被替换的情况。

先说下css var()函数正常使用,以下面的demo为例:查看图1可以看出,background-color已成功替换为具体的颜色。(其中 :root 选择器匹配文档根元素。在 HTML 中,根元素始终是 html 元素。所以var(--primart-color)会在加载时被替换成对应的#B1D7DC值。)

style.css案列如下:
:root {
--primary-color: #B1D7DC;
}
html {
background-color: var(--primary-color);
}

切回正题:那么为什么出现了有服务器出现样式加载的问题呢,笔者带着这样的问题先去看了业务的css(ps:由于业务代码属于其他厂商的,且不开源)所以笔者以demo来描述和业务场景一样的问题。下面的css是基于demo来实现与现场业务一样问题的场景。

该业务的css笔者一开始好奇只存在var()函数,而没有对函数的替换值,显然与上面所提及的案例不一致,但是访问页面如下图2所示。也是描述的状态var(--primary-color)值没有被替换。

      对比正常的weblogic服务器显示结果,该处的值是被替换成具体的颜色。那么问题就很清晰了肯定在某处提供了key值替换的功能,于是基于此搜索了业务代码发现,对应的替换放在了java的过滤器中。代码如下:可以清晰的可见String replacedText = new String(content, wrapperResponse.getCharacterEncoding());对无边码的字节数组进行创建css对象,再此过程种对css对象中对primary-color等字段进行颜色替换,最后在将文本按照对应的编码转化成无编码格式的字节数组输出文件流操作。仔细看了下这是通用的代码不存在差异,那么问题出现在哪了,于是wireshark抓了下包发现端倪如下面图3所示。服务器发过来的css的Content-Encoding是gzip的格式被压缩了,而当前过滤器的代码正好基于content内容进行更改的,因此压缩前后的内容不一致,导致文本内容替换失败。

      既然我们排查到了问题,那么接下来就是如何解决:

      通过查看服务器的代码的代码如图4所示:服务器代码存在preCompressedFile,默认值为true,即对字节数组输出流进行GZIP压缩处理。可能是某些服务器对于静态文件等资源进行传输等性能上的调优,默认的将文件流进行了压缩处理,导致了出现了上述的问题,后面我们把该服务器的preCompressedFile的属性改成false,然后再测试发现,问题解决。具体的结果我们再次抓包如图5所示。可见当前的响应格式是没有经过任何压缩处理的,至此问题解决。在下也想吐槽下,服务器作为比较中间层面的东西,很多厂商的优化应尽量考虑全客户的应用场景,这样对于排查问题等事情会简单很多。

   拓展:tomcat也支持对输出内容进行压缩处理,具体属性为server.xml中 compression=”on” 打开压缩功能。具体其他的针对某些具体的text/css等进行压缩可以设置web.xml中的配置进行设置即可。

TestFilter.java过滤器实现

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
			throws IOException, ServletException {
		HttpServletRequest httpRequest = (HttpServletRequest)request;
		String requestUri = getCanonicalURIWithoutContextPath(httpRequest);
		   if (requestUri.endsWith(".css")) {
			      replaceCssFile((ServletRequest)httpRequest, response, filterChain);
			    } else {
			    	filterChain.doFilter(request, response);
			    } 
	}

	private void replaceCssFile(ServletRequest httpRequest, ServletResponse response, FilterChain filterChain) {
	    CssResponseWrapper wrapperResponse = new CssResponseWrapper((HttpServletResponse)response);
	    try {
			filterChain.doFilter(httpRequest, (ServletResponse)wrapperResponse);
		    byte[] content = wrapperResponse.getCaptureAsBytes();
		    if (content != null && content.length > 0) {
		      String replacedText = new String(content, wrapperResponse.getCharacterEncoding());
		      Map<String, String> colorMap = new HashMap<String, String>();
		      colorMap.put("--primary-color", "#B1D7DC");
		      colorMap.put("--accent-color", "##FF3F90");
		      colorMap.put("--primaryColorOnHover", "##FF0000");

		      for (Map.Entry<String, String> entry : colorMap.entrySet())
		        replacedText = replacedText.replaceAll("var\\(--" + (String)entry.getKey() + "\\)", entry.getValue()); 
		      response.setContentLength(-1);
		      response.setContentType(wrapperResponse.getContentType());
		      ServletOutputStream out = response.getOutputStream();
		      out.write(replacedText.getBytes(wrapperResponse.getCharacterEncoding()));
		      out.flush();
		    } else {
		      response.setContentLength(-1);
		      response.setContentType(wrapperResponse.getContentType());
		      ServletOutputStream out = response.getOutputStream();
		      out.write(content);
		      out.flush();
		    } 	
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ServletException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
	}

	private String getCanonicalURIWithoutContextPath(HttpServletRequest request) {
	    if (request == null)
	        return null; 
	      StringBuilder sb = new StringBuilder();
	      if (null != (request.getServletPath()) && !"".equals(request.getServletPath()))
	        sb.append(request.getServletPath()); 
	      if (null != (request.getPathInfo()) && !"".equals(request.getPathInfo()))
	        sb.append(request.getPathInfo()); 
	      return sb.toString();
	}
style.css

html {
background-color: var(--primary-color);
}
h3 {
border-bottom: 2px solid var(--primary-color);
}
p {
   background:var(--primaryColorOnHover);
}
button {
color: var(--accent-color);
border: 1px solid var(--accent-color);
}
.test {
   background:var(--primaryColorOnHover);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值