月度归档:2017年09月

如何修复IE8浏览器下@font-face触发兼容性视图模式的Bug

源自于公开课官网的问题:https://open.163.com
本来是想打算解决公开课APM报警异常的,歪打正着看到了这个问题,就看了一下这个问题:
现象是使用Win7的IE8打开页面之后会提示

163.com的问题导致lnternet Explorer使用兼容性视图刷新网页

这个问题也是坑,百度结果不靠谱,Google又不知道怎么翻译搜索好,搞了好久,大概思路都是在crash,ie8,win7,Compatibility Mode等关键词上,其实也没有考虑别的太多的方面。由于实在是没有思路,所以来了点儿暴力招数:一个一个删除页面上的资源,找出触发Bug的情况,然后再进行分析。
最后定位到一个样式表文件在载入之后会触发页面白屏,最后又通过暴力二分法找到了受影响的语句(其实很快就找到了问题),发现@font-face在注释掉,或者不使用@font-face定义的font-family就不会出现问题。最后改变思路查找问题范围更改到font-face,ie8,crash上,结果找到了一些端倪:

I'm having a problem where icon fonts are causing IE8 to go into Compatibility Mode. And correspondingly, if IE8 is forced into Edge mode (eg. via ) then IE will crash.
来自于:https://stackoverflow.com/questions/25319643/icon-font-causes-compatibility-mode-in-ie8/29441642#29441642

从这来看这个Bug的触发是来自于IconFont使用了Private Use Area的原因,再来看一下Private Use Area是什么东西:

In Unicode, a Private Use Area (PUA) is a range of code points that, by definition, will not be assigned characters by the Unicode Consortium.[1] Currently, three private use areas are defined: one in the Basic Multilingual Plane (U+E000–U+F8FF), and one each in, and nearly covering, planes 15 and 16 (U+F0000–U+FFFFD, U+100000–U+10FFFD). The code points in these areas cannot be considered as standardized characters in Unicode itself. They are intentionally left undefined so that third parties may define their own characters without conflicting with Unicode Consortium assignments. Under the Unicode Stability Policy,[2] the Private Use Areas will remain allocated for that purpose in all future Unicode versions.
来自于:https://en.wikipedia.org/wiki/Private_Use_Areas

正常情况下其实使用Private Use Area去定义自定义符号是完全没有问题,甚至是一个正常的行为,由于IE8的具体实现我们不得而知,所以只能研究到什么行为导致的,所以解决方案也就很清楚了,避开使用Private Use Area就可以解决问题.

帮你纠正处理二进制数据时的想法

这个问题源自于我一年前做加解密的时候遇到的问题,结果最近IOS同学在做加解密时竟然遇到同样的问题,特记录一下也给各位普及一下,防止进入死胡同出不来。
一般我们在处理二进制数据时会直接读到二进制数据,自然也不会考虑到编码的问题,但在Web的海洋当中二进制传输发展较慢(主要是二进制数据处理支持较慢),所以在传输数据时习惯采用俗称的编码方式传输,这块就会出现一个问题:编码成什么样的内容?无非就是编码成字符串形式,这样就形成了字符串与二进制数据的一个对应关系,但其中有一种比较蛋疼的编码方式是直接将二进制数据本身使用字符串进行表示,比如00100011B=>23H=>”23″,11001101B=>ABH=>”AB”; WTF,这种很容易误导,以为将字符串直接转换成二进制就可以,比如前端同学会采用:

let someone = new Blob("AB", {type: "application/octet-binary"});
const fr = new FileReader();
fr.addEventListener('load',(e)=>{
    console.log(e.target.result);//retulr is ArrayBuffer
    //...do something
});
fr.readAsArrayBuffer(someone);

IOS同学可能会用:

NSData * data; 
NSString *result = [[NSString alloc] initWithData:data  encoding:NSUTF8StringEncoding]; 

直接坑死,关键地方在于这两种处理方式都是采用了字符串编码方式处理,读取的是编码后的二进制数据,也就是说是原始二进制存储数据。这种存储方式其实就和编码关系很大,如果给你传递的是GBK方式的字符串,那对应的数据又不一样了,这种直接处理的思维很容易让人陷在其中无法走出,只需要将字符串当成十六进制的数字处理,这个问题就直接解决了:

//”AB”=>ABH=>11001101B

Chrome下自签名证书提示无效的问题

其实之前就已经发现有这个问题,突然用本地调试的时候就提示证书无效,之前用的还好好的,也没有多想什么。今天刚好需要做新的项目,由于项目本身走全站HTTPS,为了能更快发现掺杂的非HTTPS资源,因此想要在本地配置一个自签名证书,发现怎么配置都不对,由于还忘记了当时配置自签名证书的方法,因此搞了好久,为了防止忘记,特地记录一下。
我看了很多关于自签名的文章,去找签名方法,但配置到apache中总会报错启动失败,这是由于签发的证书真是自签名证书,其实没有CA签名过程,具体看下例:

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

使用的是server.key签名server.csr生成server.crt文件,之前没有发现到,其实这个流程本身有点奇怪,因为本身自签名就不是认证的合法签名,这样签名之后生成的是一个CA签名,而不是域名签名。然而我老是用这种方式进行域名签名,死活不行也是很正常的。
因为我之前已经生成过ROOT CA,因此我只需要生成一个私钥、对应的证书请求文件、并使用ROOT CA生成签名证书就可以了,生成ROOT CA的方式如上面所述,在此就不在阐述

  openssl x509 -res -days 3650 -in reqFile -CA caCrtFile -CAkey caPrivateKeyFile -CAserial caSerialFile -out outCrtFile

其实一句话就可以对reqFile签名,但这种方式从Chrome58之后就不能再骗过Chrome浏览器了,会提示证书无效,也就是第一句话所说的问题。找到一篇日志解决此问题: https://medium.com/@kennychen_49868/chrome-58%E4%B8%8D%E5%85%81%E8%A8%B1%E6%B2%92%E6%9C%89san%E7%9A%84%E8%87%AA%E7%B0%BD%E6%86%91%E8%AD%89-12ca7029a933 原因及解决方法讲的很清楚,可以阅读链接文章,在此直接贴解决方案
只需要再创建一个extFile 具体内容为:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost

签名的命令行中多加一个参数 -extfile extfilePath

  openssl x509 -res -days 3650 -in reqFile -CA caCrtFile -CAkey caPrivateKeyFile -CAserial caSerialFile -extfile extFile -out outCrtFile

签名之后的证书就可以让Chrome重新显示绿锁。