记⼀次Css样式var()函数替换失败的排查过程和原因分析
(服务器GZIP压缩导致出错)
前⼏天客户现场国产服务器部署应⽤时,出现了和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, CharacterEncoding());对⽆边码的字节数组进⾏创建css对象,再此过程种对css对象中对primary-color等字段进⾏颜⾊替换,最后在将⽂本按照对应的编码转化成⽆编码格式的字节数组输出⽂件流操作。仔细看了下这是通⽤的代码不存在差异,那么问题出现在哪了,于是wireshark抓了下包发现端倪如下⾯图3所⽰。服务器发过来的css的Content-Encoding是gzip的格式被压缩了,⽽当前过滤器的代码正好基于content内容进⾏更改的,因此压缩前后的内容不⼀致,导致⽂本内容替换失败。
既然我们排查到了问题,那么接下来就是如何解决:
通过查看服务器的代码的代码如图4所⽰:服务器代码存在preCompressedFile,默认值为true,即对字节数组输出流进⾏GZIP压缩处理。可能是某些服务器对于静态⽂件等资源进⾏传输等性能上的调优,默认的将⽂件流进⾏了压缩处理,导致了出现了上述的问题,后⾯我们把该服务器的preCompressedFile的属性改成false,然后再测试发现,问题解决。具体的结果我们再次抓包如图5所⽰。可见当前的响应格式是没有经过任何压缩处理的,⾄此问题解决。在下也想吐槽下,服务器作为
⽐较中间层⾯的东西,很多⼚商的优化应尽量考虑全客户的应⽤场景,这样对于排查问题等事情会简单很多。
拓展:tomcat也⽀持对输出内容进⾏压缩处理,具体属性为l中 compression=”on” 打开压缩功能。具体其他的针对某些具体的text/css等进⾏压缩可以设置l中的配置进⾏设置即可。
TestFilter.java过滤器实现
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest)request;
String requestUri = getCanonicalURIWithoutContextPath(httpRequest);
if (dsWith(".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 = CaptureAsBytes();
if (content != null && content.length > 0) {
String replacedText = new String(content, CharacterEncoding());
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 : Set())
replacedText = placeAll("var\\(--" + (Key() + "\\)", Value());
response.setContentLength(-1);
response.ContentType());
ServletOutputStream out = OutputStream();
out.CharacterEncoding()));
out.flush();
} else {
response.setContentLength(-1);replaceall()
response.ContentType());
ServletOutputStream out = OutputStream();
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 != (ServletPath()) && !"".ServletPath()))
sb.ServletPath());
if (null != (PathInfo()) && !"".PathInfo()))
sb.PathInfo());
String();
}
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); }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。