近几年,越来越多的网站开始支持https,我们可以看到国外的比如github、谷歌、facebook;国内的有百度、淘宝、博客园、coding.net、worktile等一系列的网站。
我再最近的开发中,涉及到了一部分。我再页面中加入广告的代码,但是业务线的同事激动的告诉我他们要全站支持HTTPS,这对于我来说既兴奋又紧张,我当然对新技术充满好奇,但是我从来没有这方面的经验,为此我仔细的调查并找运维大神们问了一圈,我简单整理了一下,说一下有关于前端这边HTTPS的应对方案。
那么什么是HTTPS、它带来了什么?
从名字来看,它比http多了一个“s”,这个“s”表示安全。目的在于提供更安全的HTTP通道,即HTTP下加入SSL层并且加密。太详细的我就不再这里说了,再说我就要抄百度百科了。简单来说,不同于HTTP使用80端口,HTTPS使用443端口,HTTPS还需要一个付费的CA证书来保证安全。从另一个角度讲安全也带来了开销和通信效率的降低,这就要看产品的一个取舍了。
HTTP给前端页面带来哪些挑战,不改行不行?
1、HTTPS下不能调用HTTP静态资源:
浏览器默认是不允许在HTTPS里面引用HTTP资源的,一般都会弹出提示框,用户确认后才会继续加载,用户体验非常差。而且如果在一个HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的。Chrome 21之后,在SSL加密页面embed非SSL的Flash会怎样呢?会被默默的屏蔽掉,只留下一句console报告。浏览器为了安全,https下跨协议调用http的是不行的,控制台里会有警告。所以你只能去找https协议的 css、js资源了。也有文章说https页面中可引用http的图片,我试了一下,发现虽然不会报红错,但是会有黄色的提醒。最好的方法是使用https的资源。
2、HTTPS下不能调用HTTP的异步请求:
如果在https的页面中使用http的ajax调用。会提示跨域的报错,很明显有违ip地址、端口、协议的跨域限制。有两种方案:其一试调用https的ajax,既然页面都升级到https了那么服务接口升级也是应该的。其二既然跨域了,我们可以考虑jsonp的方案,但是jsonp 发出的是js文件请求(再次强调jsonp和ajax是两回事)。所以同上一个问题https中应用静态资源也必须是https的。所以即使是jsonp的方式也要提供jsonp接口的服务器支持https。看来异步请求也要升级到https才行。
3、不改行不行:
通过上面两个问题,不改肯定是不行的。页面的静态用不了,请求也报错,这肯定是不行的。
前端应该如何应对?
1、静态文件拉取:
首先要保证在https的页面中拉取http的静态资源。那么静态资源就必须支持https。这方面就要去抱运维大神们的大腿了,申请证书,配置到需要使用的服务器上(我们应该事先提供会用到哪些静态资源的域名)。确保可以获取https的静态资源后。我们可以考虑下一步。
2、服务升级:
同样的拿到证书后,要保证ajax的jsonp的接口支持https。这样服务端的工作就支持的差不多了。
3、页面引用:
既然我们的静态文件支持了http和https两种协议。但是静态文件并不知道页面是什么协议。我们应该怎么适应呢?引用资源的url中我们应该使用相对协议,比如
src=“http://a.com/static/a.js”
应该改为如下:去掉http:
src=“//a.com/static/a.js”
以“//”开头表示相对协议,页面使用的是什么协议,文件请求也自动是什么协议。同样的异步请求也应该这样适应。
4、对于老数据应该如何应对:
好多的url中直接就带有http:// 那是过去留下来的历史问题。这些url存在数据库中,通过同步、异步的接口来到页面上,由于https的问题我们不能直接使用,我们就要通过js改造这些http:。简单来说,就是一个正则替换
(“http://abc.com/index.html”).replace(/http:/g, "")
但是对于异步返回的json中,我们不能遍历每一个属性去替换,因为我们事先不了解json的结构,嵌套层级数,一个一个遍历也太低效了。我这里提供一个比较方便的方法,就是现将json序列化成字符串,再全局替换后反序列化。
1 var relativeHttp = function(obj){ 2 var strObj = JSON.stringify(obj); 3 var removeHttp = strObj.replace(/http:/g, ""); 4 return JSON.parse(removeHttp); 5 }
5、相对协议,永远都好用吗?
相对协议在放进标签、js异步请求是都好用。但是当url的参数中需要加入url时,就不是很好用了。我们的“//”并没有成功,我们需要根据页面的情况加入协议,拼装成完整的url,我们怎么获取协议呢?其实浏览器为我们提供了这种API window.location.protocol 如下图:
我们拿到协议后可以根据需要来使用它。