普通视图

发现新文章,点击刷新页面。
昨天以前隋堤倦客

node源码学习笔记--第二篇(最简单的模块path)

作者 隋堤倦客
2019年8月22日 01:28

这篇是正式阅读的第一篇,从最简单的path开始阅读,我记得之前在掘金收藏过node源码阅读的文章,想找来看看它们的写作思路,发现早就已经取消收藏了(大概是因为质量不高)。不过这样也好,不受到其他人思路的干扰,我的文章输出我自己的阅读收获,先尽量保持清晰。

path功能回顾

这个系列我希望能做到格式统一,第一部分先过一下API。我觉得这样做很有必要,对于不熟悉的功能可以先熟悉用法,对于熟悉的功能也可以做一个知识梳理,知道怎么用才能有机会去理解为什么这样用。

path是node中非常常用的一个模块,用来处理各种文件路径相关操作,path的API可以根据所在平台不同展现对应的行为,屏蔽了win和*nix系统之间差异。

path常见API及功能如下:

具体的功能链接里面都有,下面分析源码时候会逐个讲解,这部分就不再重复。

path API 源码阅读

path源码的最后一行如下,导出的内容就是我们require时引入的内容,这里利用process模块识别当前操作系统是否为win32,根据操作系统导出不同内容。process也是node提供的一个模块,内部肯定是要调用原生API来处理,后面还会读到这里,所以在此不作具体分析。

win32很熟悉,就是windows环境。posix是一种线程标准(详见wiki),最早为unix系统使用,后来unix-like系统也开始遵守此标准,现在Windows其实也有兼容,但是通常还是用来作为 nix 系统的代指,个人理解这里可以理解为 nix 系统。具体二者之间的平台差异会在具体API下对比分析。

1
module.exports = process.platform === 'win32' ? win32 : posix;

之后来看win32和posix两个对象,其实很简单,里面只有一些属性和方法,这些就是暴露出的path相关API,我们可以在程序中使用path加点调用的,上面已经对其进行了一一列举,下面就依次逐个分析。(因为文档上的排列顺序是按照字母表的,这里为了对应沿用下来,具体在源码中的位置可以搜索查看)

path.basename(path[, ext])

这个方法用于获取path的最后一部分,类似于Unix的basename命令,第二个参数为扩展名,如果传入会返回去除扩展名之后的结果。直接引用官方示例:

1
2
path.basename('/foo/bar/baz/asdf/quux.html'); // 返回: 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html'); // 返回: 'quux'

实现方式其实两端差异并不是很大,先看posix平台下的逻辑,最后再来看差异的部分。

这个方法的逻辑想想也知道,匹配出最后一个分隔符(posix平台为/符号),截取后面的内容,如果传入了扩展名再截下扩展名部分,返回最终结果。

进入方法首先通过validateString校验参数,如果传入的不是string会抛出错误。之后这里首先处理有扩展名的情况(扩展名长度要小于路径长度,否则视为无效,按照无扩展处理),这里从后向前遍历path,通过charCodeAt获取code,判断是否为分隔符(posix平台为/符号),最终截取首次匹配到分隔符的位置的下一个位置开始,到扩展名前一个位置结束的内容,即为返回结果。对于没传入扩展名的情况,只要截取到结尾位置即可。

对于Windows系统这里有两处不同,首先是盘符判断,Windows系统可以有多个磁盘分区,对于从根目录开始的情况,路径前面会携带盘符信息如C:,这种情况需要排除前两个字符,从第三个字符开始处理。另外,Windows的分隔符为/或\两种都可以,所以这里需要判断两种情况,在源码中的isPathSeparator方法处理了win32的两种分隔符。

特别的,在js等很多编程语言里,\为转义字符,所以想表示\字符本身需要写作\\

path.delimiter

这是一个常量,返回对应操作系统的路径定界符,路径定界符就是指并列写多个路径时候用来分隔的符号,一个常见的场景就是配置环境变量时候,对于多个值中间的分隔,Windows上为;,而在posix上则是:。在源码中也就是两个导出的属性值常量。

在程序中,我们可以这样使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// posix

console.log(process.env.PATH);
// 打印: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin'

process.env.PATH.split(path.delimiter);
// 返回: ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin']


// win32

console.log(process.env.PATH);
// 打印: 'C:\Windows\system32;C:\Windows;C:\Program Files\node\'

process.env.PATH.split(path.delimiter);
// 返回: ['C:\\Windows\\system32', 'C:\\Windows', 'C:\\Program Files\\node\\']

path.dirname(path)

这个方法用于获取path的目录名,类似于Unix的dirname命令,示例:

1
path.dirname('/foo/bar/baz/asdf/quux'); // 返回: '/foo/bar/baz/asdf'

这个方法在win32和posix上的实现方式有很大区别,首先来看比较简单的posix平台。

posix平台下的实现很简单,依旧是从后向前遍历,找到第一个分隔符截取前面内容即可,特别的,对于没匹配到的情况,绝对路径返回/相对路径返回.

在win32平台下核心处理逻辑和posix是相同的,但是关于开头的盘符相关处理有一段特有的逻辑,通过多次遍历处理最终截取正确的dirname。

path.extname(path)

返回扩展名,包括.符号,这里就是一个字符串匹配,找到最后一次出现.的位置截取后面内容,如果.出现在文件首部则返回空。

1
2
3
4
5
6
7
8
9
10
11
path.extname('index.html'); // 返回: '.html'

path.extname('index.coffee.md'); // 返回: '.md'

path.extname('index.'); // 返回: '.'

path.extname('index'); // 返回: ''

path.extname('.index'); // 返回: ''

path.extname('.index.md'); // 返回: '.md'

具体的匹配思路也没有什么特别之处,依旧是从后向前遍历,win32下需要处理首部的盘符信息。

path.format(pathObject)

path.isAbsolute(path)

判断是否为绝对路径,在posix上很简单,判断是否以/开头即可,win32上复杂一些,以盘符开头的也符合绝对路径条件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// posix

path.isAbsolute('/foo/bar'); // true
path.isAbsolute('/baz/..'); // true
path.isAbsolute('qux/'); // false
path.isAbsolute('.'); // false


// win32

path.isAbsolute('//server'); // true
path.isAbsolute('\\\\server'); // true
path.isAbsolute('C:/foo/..'); // true
path.isAbsolute('C:\\foo\\..'); // true
path.isAbsolute('bar\\baz'); // false
path.isAbsolute('bar/baz'); // false
path.isAbsolute('.'); // false

path.join([…paths])

path.normalize(path)

path.parse(path)

path.posix

返回path方法中的posix部分。在源码的结尾处有这样两行:

1
2
posix.win32 = win32.win32 = win32;
posix.posix = win32.posix = posix;

这里在导出的内容上都挂载了win32和posix两个对象的引用,无论在什么平台上,都可以通过path获取想要的对象,通过这个对象可以访问对应平台下的属性和方法。

path.relative(from, to)

path.resolve([…paths])

path.sep

一个常量,系统分隔符属性,在win32返回\,在posix返回/ ,实际上win32两种都支持,这里只返回\,同样由于转义字符的原因,源码里为\\。常见用法:

1
2
3
4
5
6
7
8
// posix

'foo/bar/baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz']


// win32

'foo\\bar\\baz'.split(path.sep); // 返回: ['foo', 'bar', 'baz']

path.toNamespacedPath(path)

这个方法只在win32生效,posix环境是一个空方法,直接返回path。关于namespace相关的内容参见这个链接,相关的东西我没使用过,源码也只是根据格式对path做了匹配。

path.win32

见path.posix。

总结

这是第一篇node源码解读文章,写的是最简单的path模块,但是真正开始写起来,要比想象的困难很多,可能也是很长时间没写作的原因吧,完成最简单的一篇用了好多天,后面我可能会适当调整方法了。

node源码学习笔记--第一篇(初心)

作者 隋堤倦客
2019年8月21日 00:15

从这一篇起要开始阅读node.js的源码了,node的源码在github上,直接clone即可,主要由JavaScript和C++编写。

为什么要写这个系列

不论是学习哪些开源的东西,源码学习永远是其中不可缺少的一部分,所有人都会告诉你一定要看源码。不过为什么要看源码,怎样去看源码,这些问题大家的答案就不同了,当然这些并不重要,我个人主要是出于一下几个原因吧。

  • 不同于大多数前端开发者,我接触JavaScript这门编程语言就是从node开始的,也就是说我学习node的时候还不会写前端,因此我对它很熟悉,这会让我对看不懂的地方也不会很排斥。
  • node是一个非常优秀的开源作品,源码里面能够学习到很多东西,有助于我获取更加有价值的东西。
  • 阅读node源码,能够把技术的使用和理解融汇贯通,我从来不希望把自己限制为某个领域的开发者,我希望的我的title是软件开发工程师,至少是web开发工程师,而不是前端开发工程师,Java、Golang、Node这些东西有精力都是值得去了解的,如果没有太多精力,我希望我能在node领域有相对深入的研究。

阅读方法

阅读源码要带着目的去读,而我的目的是要从源码中学习优秀的编码方式,因此至少在第一次阅读的时候,我不回去从node的启动流程整体去分析源码,更不会去自己编译一版node。这次阅读的重点是node源码中js编写的部分,首先从API相关源码入手,会涉及到一些架构相关源码,逐层深入零散的理解源码,最终输出的产物就是每一部分API源码实现技巧以及get到的相关知识,包括不限于网络、操作系统等。首次阅读结束后,整理一下node启动流程,阅读一下C++相关源码,本地编译出node环境进行更深入的学习。过程其实不会很短,希望有所收获。

一些其他事情

其实写这篇的时候我已经阅读了几个file了,和自己想象的还是有很大不同的,有些模块的操作基本不依赖C++端,但大部分都或多或少的有依赖,这会涉及到C++模块与JavaScript之间的链接和交互,这些部分我目前还不是很了解,需要随着阅读同时学习,这可能会使得进度变慢,但是对后续学习还是会有促进作用。开头会很难,希望能坚持下去。

下一篇是正式阅读的第一篇,就从最简单的模块path开始。

失踪人口回归--写一些要做的事

作者 隋堤倦客
2019年8月18日 15:38

初心

最近确实很久一段时间没有更新文章了,上次什么时候写的,写的什么,我已经不记得了,只知道那时候我还是一个学生,现在已经是社会工作者了。不知什么时候开始,有一些懈怠,这种感觉真的不好,却越来越严重,没办法静下心来去做好该做的事,或许我应该有些规划了。

技术成长

现在已经开始工作了,目前部门所用的技术栈又与我学习的和想要学习的东西相符,这是一种很好的体验,而我之前的学习清单也可以更深入的落地了,下面是我整理的最新的需要深耕的技术领域和目标,希望自己能够定期check。

质量检测分为S、A、B、C四种

  • S 掌握原理
  • A 熟练使用
  • B 使用过
  • C 听说过
技术内容目标质量目前状态
ReactSA-
React NativeSB+
TypescriptSB+
EggSA-
ElectronA+B-
Rx.jsCA
GraphQLB-A+
DockerCA+

先写这么多,随时会补充,这些应该是要作为长期目标的,针对以上问题会有一个针对性的check。

其他事情

叫做其他事情因为这里既包括技术相关的东西也包括非技术的东西。

这里的技术主要指的是通用能力:算法、网络、操作系统、软件工程,具体要如何去量化成长将会是后续规划的问题。

非技术上主要是个人成长的东西,我觉得比较重要的首先是英语水平、然后身体素质、产品意识等,这些会决定未来的很多事情。

想做的事

短期来看,一个不成熟的计划就是做一个给非本行业的人获取信息的一个平台,包括产品本身的构建和知识库的构建。目前这里仅仅是一个雏形。

另外就是qsls项目,第一阶段的数据清洗已经完成,后面还要有人工清洗等流程,管理后台也要搭建好,同时产品本身的开发也应该同步进行。

第一阶段目标

暂且也叫它OKR,我想以此来衡量我一个阶段的成长,每次check间隔为10到20天,更新TODO信息状态,补充下一阶段目标,因此本文长期更新,同时上面的内容有也会不断细化。

2019.10.30 – 修改

  • GraphQL 知识整理
  • qsls 项目概要设计
  • Rx.js 学习和使用

暂且如此,明天可能会更新一下,之后等待下次check。

Check 结果很不理想,可能真的难以找回那份初心了,现在每天真的很乏力,好在喜欢折腾的特点没有变,已经尝试使用 VIM 很久了,这些内容就是用 VIM 编写的,还有 TMUX 等东西,权当娱乐了,这些不重要。

接下来的周期里,可能真的得做一些正事了,以后使用 things 来归档日常任务。

网络安全xss和csrf入门

作者 隋堤倦客
2018年4月27日 07:53

在互联网的世界里面,安全始终是一个极为重要的问题。平时自己写demo时候往往会忽略这一点,但是,一旦想要成为产品,安全是一定要放在第一位的。在web开发中,理解常见的网络安全隐患,知道其原理并学会防护是一项重要的技能。

XSS

什么是xss

XSS全称跨站脚本攻击(Cross Site Scripting),是一种非常经典的网络攻击方式,它的攻击方法很简单,就是把脚本写到要攻击的网站上执行。

如何让别人的页面执行自己的脚本,这就是一个注入的过程,xss注入方式主要分两种,反射型xss和存储型xss。

存储型xss

存储型xss非常直接,向内容需要提交到数据库输入框中输入<script></script>标签,里面直接写自己的脚本,然后,数据存到数据库,别人浏览的时候从数据库读取内容,当浏览器解析到script标签的时候,就会执行里面的js代码,这就完成了一次简单的注入。注入的手段有很多,除了script之外,比如一个img标签,如果加载不到资源会触发一个onerror回调函数,这样也可以执行注入的脚本。存储型xss的特点就是,xss攻击内容是持久化的。

反射型xss

反射性xss的特点就是非持久化,需要用户交互,典型的方法比如在url参数中注入script标签,如果是需要获取请求参数的页面,页面加载的时候就会读取到脚本内容,从而执行攻击代码。这种方式工作的前提是诱导用户点击攻击url,不过脚本内容是不需要进入数据库的,进页面即可触发。

道理都是一样的,接下来就是做注入之后的事了。

一个网站上如果能随意执行其他人的脚本,其实是非常可怕的一件事。首先js能修改页面内容,能跳转链接,对方可以做很多恶意操作。而且,js可以获取cookie,cookie泄露的后果大家应该都懂。

xss防范

防范xss攻击是一个很重要的工作,最基本的原则就是,不要相信任何来自用户的输入,一切可以注入的机会都要严格防范。此外,即便保证输入安全,也要做好有不安全内容的准备,所以,在页面上展示的内容一定要经过转义编码,不要给任何外来脚本执行的机会。此外,可以将cookie设置HttpOnly,这样可以避免js获取cookie,避免了由于cookie泄露造成的危害,即便有xss漏洞,也能将损失降到最低。

CSRF

什么是CSRF

CSRF全称跨站请求伪造(Cross-site request forgery),指的是利用各种不法手段,在用户不知情的情况下以用户身份发送恶意请求。

举个简单的csrf例子,用户登录了a网站,此时登录攻击网站b,b网站如果直接跳过去操作a网站的话,是以登录用户的身份来做的,它可以在用户不知情的情况下以用户身份操控a网站,这就是csrf。

csrf防范

防范csrf的方式主要有三种:

  1. 验证HTTP Referer字段:在HTTP头中有Referer字段,它记录该HTTP请求的来源地址,如果跳转的网站与来源地址相符,那就是合法的,如果不符则可能是csrf攻击,拒绝该请求。

  2. 在请求地址中添加token并验证:在请求的时候加一个随机产生的token,token是存入数据库之后,后台返给客户端的,如果客户端再次登录的时候,后台发现token没有,或者通过查询数据库不正确,那么就拒绝该请求。

  3. 在HTTP头中自定义属性并验证:原理和上面其实一样,只是验证信息这次被加到了http请求头里面,每次只要验证即可。


以上是关于web安全的一点内容,只能算是认识了解了一下,安全无小事,网站的安全也应当高度重视。

ajax请求相关

作者 隋堤倦客
2018年2月23日 15:54

上一篇单独写的是ajax跨域,这一篇就来详细说一说ajax,ajax是现代web开发中必不可少的一部分内容,非常基础也非常重要,这篇总结一下到目前为止我对ajax的理解。

什么是ajax

ajax是web开发中的一种交互技术,全称为Asynchronous JavaScript And XMLHttpRequest,使用ajax可以实现页面局部更新,每次变化不再需要请求整个页面,之前在我web开发历史的文章中也提到过,从前的web页面每次需要更新时都必须要刷新整个页面,整体体验非常不好。ajax的出现并大量使用在web开发中绝对是颠覆性的变化,它使得开发出优秀的web应用成为现实,从此各种各样的前端技术才得以兴起。时至今日,ajax已经成为web开发中难以或缺的一部分。

ajax的核心自然就是XMLHttpRequest对象了,它存在于所有现代浏览器中(IE5 和 IE6 使用 ActiveXObject),它使得浏览器可以发出HTTP请求与接收HTTP响应。有了这一基础,剩下的就是js交互了,整个过程浏览器就可以处理,而交换数据的文档也不限于xml(现在常用json)。

ajax交互流程

一次ajax交互是浏览器向服务器请求一次数据的过程,整个过程可分为4步:

  1. 请求发起:在此阶段,由XMLHttpRequest发起一个http请求,GET、POST、PUT、DELETE、UPDATE等等都可以。
  2. 数据传送:发起请求之后就要传递数据,不同的请求方式传递数据的方式细节不同,但都是浏览器向服务器方向的,因为交互是双方的,数据传递自然很重要。
  3. 监听状态:整个请求过程结束后浏览器的任务就是等,等待服务器的响应,这个过程不会阻塞用户,只是在后台监听连接状态,这里就体现出异步的优势了。
  4. 接收响应:服务器处理完数据之后,后返回结果给浏览器,浏览器就可以接收整个请求返回的响应信息,然后本次请求结束。

以上就是一次完整的ajax交互,下面来通过代码展示一下简单的ajax流程。

代码演示

先来看代码

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();          
xhr.open('GET', url, true); // url 是一个URL
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304){
// 获得 xhr.responseText 为相应数据
}
};
xhr.send();

我们来一点点看其中涉及到的方法和相关概念,首先创建了一个XMLHttpRequest对象,然后接下来是一个open方法,第一个参数是请求方法,第二个参数是一个URL,默认情况要求同源(关于同源策略和跨域可以看我上一篇文章),第三个参数指的是是否为异步请求,默认是true可以省略。open方法结束会初始化HTTP请求参数,但是并不发送请求。

做好请求发送准备了,不过现在还不能发送请求。因为请求是异步的,我们无法获知请求的进度和响应状态,XMLHttpRequest给我们提供了一个事件onreadystatechange,我们可以通过监听这个时间来关注这种变化,所以下一步是注册onreadystatechange事件。

先了解一下readyState,当一个XMLHttpRequest初次创建时,这个readyState的值从0开始,直到接收到完整的HTTP响应,这个值增加到4,具体情况如下:

状态名称描述
0Uninitialized初始化状态。XMLHttpRequest 对象已创建或已被 abort() 方法重置。
1Openopen()方法已调用,但是 send() 方法未调用。请求还没有被发送。
2SentSend()方法已调用,HTTP 请求已发送到 Web 服务器。未接收到响应。
3Receiving所有响应头部都已经接收到。响应体开始接收但未完成。
4LoadedHTTP 响应已经完全接收。

在这里我们只要判断这个值是不是4就可以知道响应是否接收完成了。

另一个要关注的就是status,它指的就是HTTP状态码,这个大家都很熟悉了,只要是200(OK)或304(Not Modified)就是成功的请求(这里也可以关注statusText,它指的是状态码对应的名称,不常用)。此时就可以获取到响应数据了,responseText即为响应体内容(还有一个responseXML,它对请求的响应解析为XML并作为Document对象返回,不常用)。到此,请求准备完全完成。

接下来调用send方法,发送请求,其中如果是POST或PUT请求可以把请求体作为参数传入。整个请求到此就发送完成了。

XMLHttpRequest还有几个这里没涉及到的方法abort,getAllResponseHeaders,getResponseHeader,setRequestHeader,暂时用不到这里不过多介绍了。

对于ie5、6,创建xhr对象要使用new ActiveXObject(“Microsoft.XMLHTTP”),不过以后应该没用了。

以上就是原生js实现的ajax,在实际开发中我们几乎永远都不会去写ajax,封装好的ajax库有很多,比较熟悉的jquery中的$.ajax,$get,$post等等。到此,传统的基于XMLHttpRequest 实现的ajax的内容就结束了,不过现在还有一个东西需要认识一下。

fetch

XMLHttpRequest的api上面已经看到了,可以说的上很复杂了,它复杂到我们平时几乎都用不上原生api,于是,一种新的更优雅的解决方案–fetch诞生了。

首先fetch是新东西,先来看浏览器支持率:

可以看出其实不是很乐观,不过不要紧,我们可以使用polyfill来实现,所以可以直接来看fetch的例子:

1
2
3
4
5
6
7
8
9
10
11
12
fetch(url, { 
method: 'GET',
headers: new Headers({
'Accept': 'application/json'
})
}).then(res=>{
return res.json()
}).then(res=>{
console.log(res)
}).catch(err=>{
// 处理异常
})

可以看出fetch是基于promise的(关于promise相关内容在这篇文章中提到过),所以可以链式调用,整个过程不难理解,请求结果如果是json还支持直接处理,fetch的api非常实用,适合现代前端开发使用,使用React开发时候通常我们都选fetch作为数据请求工具。


至此,这篇文章内容就结束了,最后还是版权信息:尊重原创,转载分享前请先知悉作者,也欢迎指出错误不足共同交流,更多内容欢迎关注作者博客点击这里

学习socket.io

作者 隋堤倦客
2018年1月21日 10:08

在我接触过的小型类库框架中,socket.io绝对是最惊艳的一个,它可以只使用几行代码就能实现简单的聊天小程序。一直以来我都在想找机会应用到开发中,最近在写项目的时候刚好有需求了。在正式使用之前先做了一点小研究,又写了一个小的demo,在此记录一点心得。

什么是socket.io

Socket.IO是一个支持基于事件的实时双向通信的类库,它可以在任何平台,浏览器或设备上工作,同时在可靠性和速度方面有保证,可以构建实时性很强的应用。它兼容性极好,对于不兼容的环境采用降级策略,支持的浏览器最低达IE5.5。

为什么要有socket.io,它是怎么工作的,为什么它能够实现实时通讯。想要理解socket.io,还要从网络基础来谈起。

从轮询到websocket

先来看一个比较新的网络应用层协议:websocket。在传统网络应用中,大多数场景下都在使用http协议,那么有没有http处理不了或者不容易处理的问题呢?考虑一个场景,如果服务器想要给客户端推送消息,应该如何实现。在http协议之下,网络通信是只能由客户端向服务端发起的,服务器是没办法主动向客户端推送消息的,客户端要想接收服务器的消息,就得不停地向服务器发送请求,这种方式叫轮询。轮询的方式开销是很大的,因为不管有没有消息,客户端总是要去问服务器,不但低效还浪费资源,显然这不是一个很好的解决方案。还有一种长轮询,客户端发送请求之后一直等,直到服务器有返回再建立新的连接。同样也占用着不必要的资源。这一切的根源就是没有客户端的请求服务器是没办法和客户端通信的,这就是单向通信的缺陷,我们需要一种能够实现客户端服务端双向通信的技术。

websocket就是为了解决这一问题产生的,现在已经写入标准,主流浏览器基本支持。websocket同样是建立在TCP之上的,请求协议为ws或wss(加密)后面地址书写和http基本没区别,像下面这样

ws://server.example.com/chat

这就是一次websocket请求,请求头大概是这样的:

1
2
3
4
5
6
7
8
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

看起来和http很像,因为它握手阶段是要借助http协议的,不过在请求中加入了Upgrade相关内容,而相应信息是这样的:

1
2
3
4
5
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

服务端也响应了Upgrade,此时,已经和http没什么关系了,协议升级后双方建立的就是websocket连接了。只建立了一次连接,现在客户端和服务端可以实现应用层全双工通信了,整个过程如图所示:

socket.io的实现

socket.io想实现双向通信,当然websocket是必不可少的技术了,不过socket.io不仅仅是websocket的封装,在不支持websocket的环境中,socket.io还有多种轮询解决方案,确保它能够正常运行。

socket.io把看起来很复杂,很难实现的工作变得很容易,它的api很简洁,在很多实时场景下都很有用。

关于socket.io的小例子,可以参看我这篇内容

我的React之路--初识

作者 隋堤倦客
2018年1月7日 01:19

现代化前端

React.js是现代化前端三大主流框架之一。什么是现代化前端?随着node.js出现,前端工程化产生,前端开发者的工作已经早已不再是简单的画页面填数据了,曾经只会jQuery就可以完成工作的时代已经结束了。h5的出现,ajax的广泛应用,大前端时代的概念越来越清晰,web前端开发者承担的任务越来越多,移动端,桌面端,服务端的开发也受到了很多颠覆性的变革。这种变化,个人认为是一种机遇,采用工程化模式构建原本散乱无规范的前端本身就是一件好事,而拥抱这种变化,就要学习现代化前端开发的新技术。

为什么选择React

现代化前端的三大主流框架是angular,vue,react,对于前端开发者来说,下面这张图片很亲切

angular是Google推出的从angular2开始采用typescript构建,并且引入大量新的概念,通常把一代称为angular.js,angular特指2以上版本,可以理解为是一个全新的框架,位列三大框架之一的也是angular。vue是国人尤雨溪个人开发的,是一个比较难得的非常受欢迎的个人项目,也是在国际上影响力最大的国人开发的项目,是一个非常好的框架。react是facebook公司推出的,是目前三大框架中全球用户量最多,最活跃的前端框架。

前端技术的特点就是多,而且社区特别活跃,变化特别快,所以一方面个人肯定不能贪多,另一方面还要能够及时拥抱变化。三大框架angular特点学习门槛高,对后端开发者友好,vue特点渐进式,新手友好,react本身很小,系统庞大,而且思想独特。框架的好坏和难易没有必然联系,也不是复杂的就一定是最好的。就我而言,angular我不了解,作为熟悉后端开发的我也许会喜欢上它,不过我没学过。vue是我最早接触的前端框架了,对于新手来说真的容易上手,开始完全可以像引入jquery一样直接引入单个文件来使用,而且它完美的融合了其他框架的优点,写起来特别优雅,而随着项目逐渐复杂,又可以使用工程化方式构建。react与vue完全相反,一上来就要先接触构建工具,学习jsx,初学者很容易就放弃了。

我从前开发一直使用的都是vue.js,用的时间也不长,现在也在用vue写一个项目,了解了一些前端工程化的东西,vue相关内容也使用过,算是掌握基本使用吧。而对于react,从前了解的并不多,了解到它是完全基于js来构建前端,当时觉得这个东西可能更适合我,于是今年,2018年第一个小目标就是学会使用react了。

react和vue都是采用虚拟DOM,数据更新会实时响应到视图上,两者很多东西也都很相似。而不同之处,也就是最吸引我的地方,就是react颠覆了一种思想。过去的前端,都是html为主,css和js全都写在html中。而在react中,一切都是js,html是通过js对象来构建的的,只是为了易读性引入了jsx语法糖,css也完全是js对象。此外,由于react完全基于工程化前端来构建,在react中可以享受最新的es语法等等工程化带来的好处。很多人不会喜欢react也大抵是因为此,仅仅是为了构建页面js是否有必要有那么高要求,我觉得这也体现了不同人思维方式的不同。就我而言,服务端编程出身,一直在和数据和逻辑打交道,页面展示布局一直都不是强项,也不够敏感。react能够把逻辑程序设计的体验带到页面设计上,大概是它最大的魅力吧。

react系列的认识

无论是react.js还是vue.js本身都是只是一个视图层解决方案,要想构建一个完整的前端工程这只是其中一部分。曾经使用vue.js时候,使用过vue+vue-router+vuex+axios的组合,而对于react也是需要有这么一套完整的集合的。而且选择也不唯一,按照目前来看,至少要学习redux,react-router,后面还会有很多,随着学习会进一步总结经验。特别的,学习react当然少不了react native,这是一个移动端的开发框架。这样算起来,要学习的东西其实很多,这篇是开始的一篇,只是谈一谈简单地认识,后面学习的过程中会有经验记录,如果可以后面还会有react和vue的对比。

❌
❌