iPhone 屏幕一些事

今天看了下 iPhone X 的屏幕参数,发现它的分辨率达 2436 x 1125,和用的 DELL 2K 显示器几乎相同,但尺寸上的对比差别却是巨大。不得不感慨。

于是就总结了 iPhone 这些年的屏幕演变,一件很好玩的事情。


iPhone 2G, 3G, 3GS

从最初代的 iPhone 开始,Jobs 定下了一个尺寸 3.5 寸,认为这是人手最适合的大小,并一直的坚持着。

这时的工艺水平,还只是普通的高分屏水准。分辨率维持在 320 x 480,PPI 为 163

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
3.5 163 320 x 480 1 320 x 480 -


iPhone 4, 4s

3GS 那圆坨坨的造型深入人心,于是在 4 的方正预告之时,办公时还出现过一些争论,不过人总是向前看的,4 的设计很快征服了所有人,特别是前后玻璃工业水平所带来的震撼,无与伦比!

4 还带来了视觉认知上的第一次升级,Retina 屏,也视网膜屏,这个原理很简单,就是以前固定大小放一个显示单位,现在放4个。视觉的改变就是颗粒感一下子就没有了,那清晰度,在两个手机间稍有对比,就会感动的落泪。

同样是 3.5 寸,分辨率变成了 640 x 960,起因是 PPI x 2,由 163 变成了 326。

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
3.5 326 320 x 480 2x 640 × 960 -

苹果最牛的地方不是发明一个新东西,而是把这个已有的东西,从一些应用变成全民应用。像不像 Martin Flower


iPhone 5, 5s, 5c, SE

有人说 iPhone 5 是 Jobs 走前定下的最后一个手机的样式,所以是他最终的杰作。

5 出来时的变化,其实是让不少人也纠结了下的,多出一块下巴,是显示信息更多了,还是变得不好拿了。

不过当时的手机世界是 Apple 坚持不造大屏,所以其它手机在大屏的领域不断开拓,也有了不少的市场。

带给程序上的变化就是,以前简单的按点布局的方式不奏效了。要有一套新的布局系统了。就是 AutoLayout。不过更多人用的方式是,判断机型,如果是 5,就把高度算到 568,否则还是 480,又安稳的过了两年。

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
4 326 320 × 568 2x 640 × 1136 -


iPhone 6, 6s, 7, 8

iPhone 6 的出现是讨人喜欢的,同时有 6 和 6 Plus,Apple 终于打破了 Samsung 在大屏的垄断,有人说这是没有了 Jobs 的后时代 Apple 在向市场妥协。

当时中国不在首发区,好多人从 HK,JP 进行代购,海关当时查的很紧,我的 日本代购的 6 Plus 还交了 550 的海关税,并且附带了3年的拍照咔嚓声。

6 时代的屏幕完全的变化了,Point 变为 375 x 667,PPI 依然为 326,也就是 2x 渲染,分辨率为 750 x1134

从此 Autolayout 完全被用上了。

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
4.7 326 375 × 667 2x 750 × 1334 -


iPhone 6+, 6s+, 7+, 8 +

但 6 Plus 就很有意思了。

它的 Point 为 414 x 736 ,然后按照 @3x 渲染,理论上的分辨率应该是 1242 × 2208,但实际 PPI 仅为 401,物理分辨率 1920x1080,在向屏幕物理渲染时,要进行一次缩放 ÷1.15

于是这对 6 Plus 带来了不小的性能问题,3倍渲染,再 ÷1.15 缩放渲染,导致在动画多的应用中出现很多的卡顿。6s Plus 因为内顿升级为 2G,CPU 也进行了升级,卡顿要好太多。

为什么出现这样的渲染机制,猜想是更高 PPI 的屏幕成本较高,2@ 渲染又会降低清晰度。所以这就变成了这种方案。

这个模型被用了 4 年,直到 iPhone 10 周年时,Apple 依然用这个模型生产了 8和 8 Plus,不过可被看作为 iPhone X 这朵红花的绿叶吧。

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
5.5 401 414 × 736 3x 1242 × 2208 1080 × 1920


iPhone X

iPhone X 的变化有种当年 4 出现时的感觉,砰然心动。

不过无边框屏在很多设备上已经有了,Apple 从来不会过于创新,只会在最合适的时机推出产品。

屏幕的变化是多了一个刘海,达 5.8 寸的 OLED 屏幕,不过由于是无边框屏,整机的尺寸与 8 差不多持平。

不过对渲染无变化,只是在设计时,要考虑一些东西。

屏幕的 Points 为 375 x 812,依然是 3x 渲染,分辨率为 1125 x 2436,不过这次 Apple 真的是做到了 3x PPI 的屏幕,高达 458 PPI,再无需向下缩放 1.15 倍了。这也是 iPhone X 售价高达 $999 的原因之一吧。

Spec

Size PPI Points Render @ Rendered Pixels Physical Pixels
5.8 458 375 × 812 3x 1125 × 2436 -


Spec 总览

Device Size PPI Points Render @ Rendered Pixels Physical Pixels
iPhone 2G,3G,3GS 3.5 163 320 x 480 1 320 x 480 -
iPhone 4,4s 3.5 163 320 x 480 1 320 x 480 -
iPhone 5,5s,5c,SE 4 326 320 × 568 2x 640×1136 -
iPhone 6,6s,7,8 4.7 326 375 × 667 2x 750 × 1334 -
iPhone 6+,6s+,7+,8+ 5.5 401 414 × 736 3x 1242 × 2208 1080 × 1920
iPhone X 5.8 458 375 × 812 3x 1125 × 2436 -


REF::

也议全栈

当代社会的总趋势是越来越复杂,应对这种趋势的办法就是封装,把一个领域里的知识包装进一个黑盒,然后提供几个接口。

就像电视机,那里面的东西复杂的去了,但对用户来说,就一个遥控器。电视机就是一个封装,提供了遥控器就是这个接口。

封装就会带来行业的差异越来越细。还拿上个列子,遥控器里面也有一些组件,像微型电池,电池和遥控器电路板也是两个很专业的领域,他们两个通过一种接口在另一个维度进行合作,这个接口可被理解为微型电子的正负极和它的样式。

这种封装在人类的进化史上就叫分工。人的大脑有限,所能理解的事物也有限。所以人们只能复杂的世界中找到一个领域,然后进去专研。

分工和封装是同步的,人们也越来在越在自己的领域深挖,变成一个专业的人才。

但这也带来了一些问题,跨领域的沟通成本越来越高,有模式就有反模式。有些人会越来越深入单一领域,但有人就会跨领域发展,叫做通材。

专才和通才的没有优劣之分,也没有高下区别。

但时势不停发生变化,每个行业,每家公司总要经过几个不同的阶段,在这些阶段中,会随着需求的不同,而对不同的人的渴望度不同,所以就会表现出不行的价格,注意不是价值。

在计算机编程行业里,也遵循着这个理论。

在设备上,有 iOS,Android 和 Web,在层级上,有前端,中端,后端和数据库,在专业领域上,又有音视频,网络,压缩等。以上这些分类法只是用来举例。

在外界看来都是同一类的工程师,但里面的划分就有这么多种。所谓的隔行如隔山。因为太复杂了,只能继续通过接口来相互通信。

那个行业的通才呢,就是跨越多种语言,多种层级间的人,近几年有个专有名词,叫作全栈工程师。

从社会总理论上来讲,这个是一个发展的方向,但因为领域比较新,所以在这方面的认知还没达到统一,关于全栈的争论也就比较多。

UPS - 数据安全的必选项

最近上海的天是这样子的。

后果是偶尔停电,偶尔大雷下来之前,会跳电,空气开关会跳掉,对于一个有着家庭数据中心的人来说,真是心疼呀。要行动起来,用买买买来解决问题。

那这次要买的是什么呢,当然就是解决电的 UPS 啦。

目标

  • 体型较小并美观
  • 电的要求不高
  • 防雷,防浪涌
  • 断电后能通知 NAS / Mac 进行关机

看完这些,网上对比下来,其实很快就锁定了,只是细节都没有描述,也就是评测不多。于是只能自己买回来后进行评测了。

这里选中的是 APC-BR550G,APC 没听过,不过网上评价不错,而且群晖原生支持。

购买

京东下单,两天后才想起买的东西,原来并不是京东配送,而是其它一个小快递公司从广州配行的配送。

东西到了后,发现还是挺重的,看了下说明书,超级复杂,都好几类电源口,不过我的需求比较简单,只是接出一个插座,把 NAS,光猫,路由器,移动硬盘接在上面。

效果

APC 提供了一根数据线,一头是 RJ45 网线口,另一端是 USB,USB 接入 NAS 后,在后台设置中,立即就发现了 UPS,进行开启就可以了。

这就是最终效果图:

HiDPI 解析

最近研究显示器时,朋友一直在讲一个词,叫 HiDPI,于是做了些笔记。

几个参数

  • pixel/px 就是显示器上一个独立可以显示的点,显示器由很多这样的点排列组成。
  • point/pt point 在一个指标下就是一个固定的长度,比如说 72,就是指 1/72 英寸,在普通显示情况下,pt值是等于px 值的。但一些情况不行了,像retina 下,4个 px 才等于一个 pt。
  • PPI(Pixels per inch) 是每英寸上的点数,跟尺寸无关,越大显示的点越多,就越清晰。
  • Display resolution 显示器上一共有的点数,和尺寸有关,也和 PPI 有关,是 PPI * 尺寸

iPhone 6 Plus 诡异的分辨率

iPhone 6 和 6+ 虽然是大小差不多,但在意义上却有点不尽相同,感觉 6+ 更接近一个 iPad Mini。

6 在显示参数上和 5S 是保持一致的,像 PPI 都是 326,也就是经典的 @2x 素材,只是物理屏幕变化, Point 也相应的增大为 375 × 667。设计师要做的就是注意尺寸变大后的留白,开发所要做的就是用相对布局。

6+ 就不同了,在渲染时用的是 @3x,理论上,PPI 应该是 163*3=489, Points 为 736 x 414,对应 3x 分辨率应为 2001x1125。但实际上,PPI 为 401;分辨率为 1920x1080,是标准的 PPI x 2.46,

在实际渲染时,6+ 也是先按照 @3x 2001x1125 来渲染,然后整体缩放 1.15 倍,到 1920*1080

显示器分辨率

从 iPhone 为入口再来理解显示器 HiDPI。

所以最好的情况只有一种,就是显示器上,用显卡渲染出四个点,做成一个 Point,对应到显示器的4个点上。这也是 Retain 的显示原理。这样是最清晰的,显示所渲染的每一个点都能在显示器上还原。

然后就是让显卡渲染出显示器的分辨率,一个点做为一个 point,这样的利用率是最高的,但字就会比较小。

举个例子,我们常见的 2.5K, 4K, 5K 分辨率。

设备 设备分辨率 HiDPI
2.5K 2560x1440 1280x720
4K 3840x2160 1920x1080
5K 5120x2880 2560x1440

以我最爱的分辨率 2.5K 来看,那开启 HiDPI 后的最佳分辨率就是 5K。

但 4K 分辨率依然可以按 2.5K 来进行 HiDPI 来渲染,那是怎么回事呢?

答案很简单,和 iPhone 7+ 的原理是一样的,显卡仍按 @2x 5120x2880 来渲染,然后再进行缩放到 3840x2160 进行显示。当然这样会造成显示的不清晰,同时也会产生资源的浪费

Macbook Pro - Retina display

先来看看 rMBP 15 的显示参数:

13.3-inch (diagonal) LED-backlit display with IPS technology; 2560-by-1600 native resolution at 227 pixels per inch with support for millions of colors

Supported scaled resolutions:

  • 1680 by 1050
  • 1440 by 900
  • 1280 by 800
  • 1024 by 640

从以上参数来看,它的显示器分辨率是 2560x1600,比 DELL U2515 还高,但因为屏幕小,所以官方认为这么高的分辨率没有什么意义,就在选项中只支持了四种分辨率。

所以,它理论上都是开启 HiDPI 的,1280x800 是它最佳分辨率。其它分辨率都要进行一些显示上的缩放。

REF::

the division in software engineering

理解分工

分工带来效能,当带社会由经济学的分工效应,所带来前所未有的发展。

如果你去看每一个行业。

我曾对装修进行过观察,一个再小的工程,如果想自己做,就会发现陷入了一场灾难。而那个衣着不整的民工,却可以不费力的做到一种完美。虽然你可能感觉智力领先。

这就是分工的结果。每个人在自己的行业不断的专研,积累经验,合起来创建更大的财富。

那软件行业呢。

也同样遵循了这个定律,从设计到代码,从产品到交互,从开发到测试,从管理到架构。

这是我们能看到的方向上的不同。

即使在同一个方向上,也会有着更细致的划分。

iOS, android, Web,

性能测试,功能测试,集成测试,

分工是什么,是因为时代的知识发生了爆炸,不再像以前一样,只有经典,而我们的个人时间,能力有限,只能注重于一个领域,去深入。

当然,除了这一点之外,还有一个解释,就是工作太复杂,也不再是一个人能完成的,需要合作。合作带来分工。

分工和组织

分工的不同,也是组织的聚合。

相同的分工会聚在一起,形成自己的知识体系的交流。

但不同分工通过产品、项目形式聚合在一起,进行跨专业的合作。

这就是一个公司最基本的团队模型。

软件工程中的合作

工种的不同,其实也反应在工作中的依赖。

像开发依赖设计交互,设计依赖产品,而测试又依赖开发,

所以,这个合作本身就有着一个链式的关系,如果在设计流程时,不考虑这层关系。那一定是会出问题的。

反模式

社会的永恒定律就是不会存在唯一真理,有模式就会有反模式。

分工带来的坏处是什么呢?

从软件工程上来讲,分工带来年问题就是大家相互不了解,在一起做事的沟通成本就要高很多。

从专业的术语来讲,就是要做到边界冗余。所以我们常提到高内聚,低耦合。差不多一个道理。

有时在一起交流的复杂度被拉高了太多,于是就有了跨专业的人。就是全栈。

全栈更多的不应该是写代码飞快,而是它能主导一场沟通的顺畅。站在更高点上,提出合理的意见。

当然,全栈是不容易的。

niu ebike

我加入了一个 BMW群,里面的车主都是 BMW, 当然除了我,不过这次是这些车主都升级了另一样,成为了小牛电动车的车主,当然还是除了我。

6000块的电动车,值吗

对这个品牌没有感觉,所以一个 5000 多的电动车感觉还是贵了不少。毕竟普通的一辆只要 2000 块。款式也不错。

6000 块是我一年的油钱了,而且是每天跨越上海来回。

安全

电动车是现在路上最恐怖的一个东西,有时会逆行在汽车道上,有时会忽然出现在你的车前。

而且出现问题都很麻烦,所以我也不是推荐。

共享电车

上海现在很多共享电动车,就绿色的那个,2块钱一小时,还是挺方便的,有时去个远一点的地方就会去找一下。

但和初期共享单车一样,有时会找不到,现在用的也少了。

短距离出行方案

买了的人还是挺满意是,说这是短距离出行的最佳方案。不过他们可能忘了这个夏天太多的雷雨了。

回想自己,周未出行,除了开车,都是地铁公交或步行,还真对单车需求比较少。

还是觉得有一辆车多开开会更省钱省心省力。

一场由 DBA 犯错,外键放大的事故分析

本来注定平淡的一天,就像骄阳下的树叶,没有一点精神。

日常修正

批了一个数据修正的单子,产品上有一个评价的功能,从设计时就坚持公平公正,但还是没顶住运营的压力,经常会删除一些不好的评论。与是就会经常的修正线上的数据。典型的理想和现实的差别。

紧急事件

十一点钟,忽然运营反馈老师的课程不见了,刚开始以为这个老师重新注册了 id,或者其它。慢慢的反馈越来越多,感觉有点头大。

然而越来越多的消息指向问题,来自外界和内部。

初步猜想

刚好,因为公司泄露 appkey 的事情闹得满城风雨,在想是不是因为哪些密码被泄露然后导致有人黑我们。

这种阴谋论细想就不大可能了,有谁能这么精确的知道我们的数据模型,所有丢失的课程都是一些好的课程。而且就算拿到 DB 密码,也需要在内网的某个环境,又懂业务,又懂技术,这几个人就在我们面前呀。

又花了不少时间,排除另一个论证。

排除一切不可能的,剩下的即使再不可能,那也是真相。

问题在 DBA?

这时,把想法又放回到数据修正时的操作。

发现 DB 中的数据有几个点也指向这里,比如说数据在上午9点多时,id 从 8k 跳到 98w。

于是开始讨论方案,最后选择从昨晚的备份中恢复。

下午3点多钟,困的想抽烟,最后用一瓶可乐解决。

第一张表恢复完,发现搜索可以,但不能用分类筛选,再恢复第2张 2W 量级的 tag 关联表。

本以为完事了,结果产品反馈,用户的订阅数据也丢失了一部分。

此时,感觉就像个无底洞,到底干了什么。

订阅记录的量级在 10M,这种可不像上两张表,几分钟进行恢复。而是达数小时的重新写回数据库。

恢复过程中,也想了下原因。

假设

DBA 拿到用于修正数据的 CSV 的数据后,用 MySQL 的 replace into 方法,对课程表进行更新,但不小心将一些课程进行了删除。

本以为只有 10K 条数据的,也没大放心上,照理做任务前先做了备份。

但这几张表是历史老表,表间是有外键关联的。

于是主表的 ID 被删除之后,导致 20K 的标签表和 10M 的用户记录表都被删除或者引用变为空。

外键

对于外键,各说纷纭,目前主流的观点是不用外键,毕竟孤岛数据已经不是问题。

但外键引发的问题远远大于几个孤岛数据。

完结

整个恢复工作一直进行到深夜,为了数据安全,是用单行恢复的方式。

这就是一个典型的操作时犯傻,外键引用放大的事件。

JavaScript 模块化之路

我们都知道 js 在诞生时,都只是为了操作一些 dom,所以也就是被随意的写在一个 js 文件里,放上几个 function,绑定上 document.ready,或者是某个 button 的 click 事件。

但恰恰历史选择了 js,这门语言被无限制的放大使用场景。以前的种种简单都变成了束缚。如何在大型应用中使用 js 成了一个重大话题。

模块化

现代软件的构成基石就是模块化,

- 模块定义

模块可以有很多种形式,一个完成可用功能的函数,类语言中的一个类文件,

- 引用机制

模块还需要一种引用机制。让模块可被其它模块所使用。除了定义。

物理模块,引用模块。

如果从这个角度来看,就是你要引用的模块,是不是在同一个文件中。如果是,那就是一个引用型模块。如果不是,还需要找到对应的模块。

JS 的模块化之路

Object

这种方式,把所有的变量,函数封装在一个 Object 里,来实现模块化,缺点是,里面的变量都能被直接读取,所有的函数都被暴露。

1
2
3
4
5
6
7
const study = {
let _count = 0;
method() {
//...
};
}

它是 new Object 形式的缩写:

1
2
3
4
5
6
7
var module1 = new Object({
_name : 'foo',
 
method : function (){
  //...
 }
});

funcation

使用立即执行函数,可以将内部的变量的访问被锁住。

1
2
3
4
5
6
7
8
9
10
11
var module = (function() {
var _name = 'foo';
var method = function() {
// ...
};
return {
method: method
};
})();

这样,只能访问到 return 函数中提供的方法 method,里面的变量是不可见的。即使有其它方法,如果不在 return 中绑定,也是不可见的。

Class

ES 2015 中提出了 Class,这是个好东西,因为它符合了当下主流主言的语法,贴近人类思想,而且对继承等进行了修正。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo {
construct() {
this.name = 'foo';
this.objectMethod = function { return 'objectMethod'}
}
prototypeMethod() {
return 'classMethod';
}
static classMethod() {
return 'classMethod';
}
}

Class 解决了变量作用域的问题。

这样,之前两种的模块方式,都可以用 Class 代替掉。
之前,object 的 prototype 可以用 static method 来代替。

class 是个语法糖

把上面的类定义,转成之前的 ES5 语法,是可以对应上的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Foo() {
this.name = 'foo';
this.objectMethod = function() {
return 'objectMethod';
}
}
Foo.classVariable = 'classVariable';
Foo.classMethod = function() { return 'classMethod'};
Foo.prototype.color = "red";
Foo.prototype.prototypeMethod = function() {
return "prototypeMethod" + this.name + this.color;
}

使用:

1
2
3
var foo = new Foo();
var temp = foo.name;
foo.method();

原型链方法函数是读写不对称,默认它是在prototype 的,但如果往这个上面写值的话,就会被复制一份到对象上去。

像一些变量,不可能在每个实例间共享的,所以它一定是实例级的,实例方法变量,会加在每一个实例上,而原型方法变量,则是共享的,但一量为原型方法变量进行赋值,其实是在实例上放上一个同名的方法,依据 JS 原型链查找顺序,只会用最近的方法变量。

除了模块的定义之外,模块的引用也有多条路在走。

  • CommonJS(require)
  • AMD
  • ES Module(import)

CommonJS

module.export()

1
module.exports = function (x){ console.log(x);};

require

1
var foo = require('foo');

ES Module

export & import

因为ES6模块是静态加载,而CommonJS模块只有运行时才知道输出哪些接口。

因为它是 static ,所以可以编译优化。

https://github.com/joshgav/CTC/blob/b50b790a89ea8c7271cee2356f6ee6abf8224906/meetings/2017-01-11.md#rewrite-002---esm-node-eps39

ES Module 的现状

  • Edge 第一个开启
  • WebKit 已开启
  • Firefox 已开启
  • Chrome 61 即将开启
  • Node.js …

可以看到在 2017 年,除了 Node,其它浏览器均已支持 ES Module。代码编译的时代即将属于历史。

SNI 问题及探究

最近 Android 一直报一个错误,错误显示为:

Hostname in certificate didn’t match

1
2
javax.net.ssl.SSLException: hostname in certificate didn't match:
<hs.hjf.cn> != <*.b0.upaiyun.com> OR <*.b0.upaiyun.com>

简言之,就是你请求服务器中的证书集中未包含当前域名的证书。

初判断

吐槽下,国内的 CDN 全是问题,写出来都是一本厚厚的书了,出这个问题时,刚好所有端都碰上 CDN 问题,所以先是从这方面着手,随着时间演进,慢慢的成了问题只出现在 Android 上。

才开始想着从 Android 上找问题,后来证实是 Android 上用的一个 Network Library 不支持 SNI 所导致。

SNI 的来历

Server Name Indication (SNI) is an extension to the TLS computer networking protocol[1] by which a client indicates which hostname it is attempting to connect to at the start of the handshaking process.

简单来说,就是如果一台机器上部署多个 HTTPS 站点,对应多张证书,应用服务器在响应时,无法确定用哪一张证书来对数据进行签名。为解决这个问题就提出了 SNI,即在 Client Hello 时,告诉用哪一张证书。

这个协议于 2004 年提出,2006 年被 OpenSSL 所加入,次年发布。

支持

目前 SNI 几乎被所有的软件和库所支持。

- Desktop Browsers

  • Internet Explorer 7 and later
  • Firefox 2
  • Opera 8 with TLS 1.1 enabled
  • Google Chrome: Chrome 6 and later
  • Safari 2.1 and later (requires OS X 10.5.6 and later or Windows Vista and later).

- Mobile Browsers

  • Mobile Safari for iOS 4.0
  • Android 3.0 (Honeycomb) and later
  • Windows Phone 7

- Libraries

这个具体就不列了,可以具体去查。提一下本次 Android 上的库吧,5.0 之前,Android 上没有自己实现网络库,用的是 Apache HttpClient,项目中用的是 async-http,另一套封装。

android-async-http

从 Issue 和源码中确实没有关于 SNI 的实现,建议使用这个库的项目尽快升级。

okhttp

okhttp 是现在 Android 上的主流,系统的 HttpURLConnection 使用不是很高。不过可以看到它也是 2014 年,才支持 SNI 的。

解决方案

除了让服务器默认使用这张证书进行签名,还能做的就是让客户端禁止 HTTPS 校验。

这样的坏处就是任何证书签名的内容就都是被信任的,数据依然存在被修改的可能性,HTTPS 的意义也就不在了,可以说花了精力接入了个假的 HTTPS。

SNI 调试方法

SNI 发生在 OSI 模型中的第六层,在 TLSV2 中。可以通过 Wireshark 这样的抓包工具来进行分析。

如果想验证这个过程,可以通过 openssl 命令来进行:

1
$ openssl s_client -servername hs.hjf.cn -tlsextdebug -msg -connect hs.hjf.cn:443

安全原因,这里的域名是假的,如果需要真实数据,可自己配置域名

1
2
3
4
5
6
7
---
Certificate chain
0 s:/C=CN/ST=shanghai/L=shanghai/O=Shanghai xxx Communications Co.,Ltd/OU=Administration Department/CN=*.hjf.cn
i:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
---

如果取消 servername 这个参数,会发现服务端用了一张默认的证书来进行签发了。这张证书上所包含的域名是 b0.upaiyun.com,这是又拍云提供的 CDN 服务。

1
2
3
4
5
6
7
8
9
---
Certificate chain
0 s:/C=CN/ST=zhejiang/L=hangzhou/O=Hangzhou Weiju Network Ltd./OU=\xE6\x8A\x80\xE6\x9C\xAF\xE9\x83\xA8/CN=*.b0.upaiyun.com
i:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
1 s:/C=US/O=GeoTrust Inc./CN=GeoTrust SSL CA - G3
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
---