读完了《图解HTTP》,就算是对计算机网络和HTTP部分内容做了个温习吧。同步做了整理,以便加强记忆和后面回顾。

概述

请求报文构成:

  • 方法
  • URI(绝对或是相对)
  • HTTP版本
  • 请求首部
  • 内容实体

响应报文构成:

  • HTTP版本号
  • 状态码
  • 状态码原语
  • 响应头部
  • 响应主体

请求URI是服务器本身时,可以用*代替URI。

可用的方法列表:

  • GET 获取资源
  • POST 传输信息
  • PUT 传输文件,没有用户验证机制,很少用到
  • DELETE 删除文件,同上,很少用到
  • HEAD 获得响应头部,不返回主体
  • OPTIONS 询问支持方法
  • CONNECT 用来建立HTTPS连接的隧道
  • TRACE 追踪路径上的所有服务器节点,很少用到

其中后面三个是HTTP1.1才开始支持的。

持久化

在HTTP1.1后,HTTP建立的TCP连接默认是长连接(keep-alive),避免不必要的多次TCP握手和挥手。在此基础上,客户端可以同时向服务端发起多个资源请求。

状态化

HTTP本身是无状态的。通过cookie实现状态化,cookie通过服务端在响应头部的set-cookie字段下发,设置信息、使用范围、过期时间等内容。客户端在使用范围内的请求默认会携带上cookie信息。

HTTP报文结构

  • 请求首部和主体通过CR+LF分割开来
  • 报文编码
    • 编码压缩
      • gzip (GNU zip)
      • compress(UNIX compress)
      • deflate(zlib)
      • indentity(不压缩)
    • 分块发送
    • 多部分发送(multipart)
      • multipart/form-data 表单文件上传,用boundary字符--表示新的part的开始
      • multipart/byterange 配合206响应只包含了部分数据时使用
    • 部分发送
      • Range指定字节范围
      • 206响应状态码
  • 内容协商
    • 双方就合适的语言、字符集、编码方式、过期时间进行协商

HTTP状态码

  • 1xx 这一类型的状态码,代表请求已被接受,需要继续处理
    • 100 Continue:客户端应当继续发送请求。
    • 101 Switching Protocals:将通过Upgrade消息头通知客户端采用不同的协议来完成这个请求。
  • 2xx 成功:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。
    • 200 OK:请求已成功,在方法时HEAD时不返回响应主体
    • 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容,用户浏览器应保留发送了该请求的页面
    • 205 Reset Content:和204的唯一不同是返回此状态码的响应要求请求者重置文档视图
    • 206 Partial Content:服务器已经成功处理了部分GET请求。请求必须包含Range头信息来指示客户端希望得到的内容范围,返回使用Content-Range多用于下载工具
  • 3xx 重定向:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址在本次响应的Location域中指明。
    • 300 Multiple Choices:被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
    • 301 Moved Permanently:被请求的资源已永久移动到新位置,建议使用Location中的新地址
    • 302 Found:请求的资源现在临时从不同的URI响应请求
    • 303 See Other:和302的区别是,客户端应当采用GET的方式访问新的资源
    • 304 Not Modified:如果客户端发送了一个带条件(包括缓存相关的请求头部)的GET请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变
    • 305 Use Proxy:被请求的资源必须通过指定的代理才能被访问
  • 4xx 客户端错误:客户端发生了错误
    • 400 Bad Request:由于包含语法错误,当前请求无法被服务器理解
    • 401 Unauthorized:当前请求需要用户验证,或用户未通过验证。
    • 403 Forbidden:服务器已经理解请求,但是拒绝执行它
    • 404 Not Found:资源未被在服务器上发现
    • 405 Method Not Allowed:请求行中指定的请求方法不能被用于请求相应的资源,响应中必须返回一个Allow头信息用以表示出当前资源能够接受的请求方法的列表
    • 406 Not Acceptable:请求的资源的内容特性无法满足请求头中的条件
    • 413 Request Entity Too Large
    • 414 Request-URI Too Long
  • 5xx 服务器错误:服务器在处理请求的过程中有错误发生
    • 500 Internal Server Error:这个问题会在服务器的代码出错时出现
    • 501 Not Implemented:服务器不支持当前请求所需要的某个功能
    • 502 Bad GateWay:作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应
    • 503 Service Unavailable:临时的服务器维护或者过载。这个状况是临时的,并且将在一段时间以后恢复。
    • 504 Gateway Timeout:作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器或者辅助服务器收到响应

协作机制

  • 代理(Proxy),单纯转发HTTP请求,会在响应头部的Via字段留下痕迹
  • 网关(Gateway),隔绝服务器和客户端,有安全、计费等逻辑
  • 隧道(tunnel),基于协议搭建,保证传输安全,对用户侧透明
  • 缓存(Cache),本地、服务端二级缓存,加快响应时间,有过期时间

报文头部

  • 首部用来进行连接的各种信息描述。每个首部的字段用字段名和值组成,两者用:隔开。
  • 首部分为端到端和逐跳两类,前者在报文转发的整个过程都保留,后者在转发后就会丢弃。典型的逐条首部有Connection, Keep-Alive, Transfer-Encoding, Upgrade

通用首部

Cache-Control

客户端和服务端协商缓存机制。配合下面一些首部字段使用:

  • Etag
  • Last-Modified
  • Expires(HTTP1.0)
  • Pragma(HTTP1.0)
  • Age(HTTP1.0)
  • If-None-Match
  • If-Not-Modified-Since

Cache-Control有下面一些可配置项。

缓冲能力上,

  • private,缓存只针对当前用户而言
  • public,缓存对所有用户生效
  • no-cache,始终对缓存进行过期验证
  • no-store,不允许缓存

过期时间上,

  • min-fresh,返回指定时间范围内的非过期资源
  • max-stale,返回指定时间范围内过期、非过期资源
  • max-age,单位:秒,最大缓存时间
  • s-max-age,同上,只用于CDN缓存

二次验证上,

  • only-if-cached,强制从缓存服务器中获取内容
  • immutable,一旦缓存不可更改
  • must-revalidate,即使本地已缓存,仍要求检查CDN缓存
  • proxy-revalidate,缓存服务器必须检查源内容是否改变

Connection

管理连接,主要有两个用途。

  • 指定不希望转发给代理的字段
  • 管理持久连接。使用Connection: Keep-Alive建立连接(HTTP1.1默认行为),使用Connection: Close终止连接

Date

报文创建时间。行如“Date: Tue, 03 Jul 2012 04:31:12 GMT”

Pragma

历史遗留字段。Pragma: no-cache等同于Cache-Control: no-cache

除此外还有:

  • Trailer,说明报文主体中记录的首部字段
  • Transfer-Encoding,分段传输的主体编码
  • Upgrade,切换协议,配合Connection: Upgrade使用
  • Via,标明沿途的整条路径
  • Warning,缓存相关警告

请求首部

  • Accept 接受文件的类型,类型间可以指定q=x表示权重值,x的取值在0到1之间。下同
  • Accept-Charset 可以接受的文件字符集
  • Accept-Encoding 可以接受的文件编码,有gzip,compress,deflate,indentity几种
  • Accept-Language 可接受的语言
  • Authorization 服务端需要的用户验证信息
  • Age 从缓存实体产生到现在经历的时间
  • Expect 期望的服务端返回状态码,服务端无法满足时返回417状态码,客户端等待服务端100响应时发送的请求都要带上该字段
  • Host 服务器的主机名,通常是请求资源的URL
  • If-Match 需要匹配的Etag,不满足时返回412,表示不满足条件
  • If-Modified-Since 返回指定日期后的新内容,否则返回304
  • If-Unmodified-Since 类似上
  • If-Range 类似If-Match不过是范围匹配
  • Max-Forwards 报文最多转发次数,通常配合TRACE方法使用
  • Proxy-Authorization 代理服务端需要的用户验证信息
  • Range 请求资源的部分内容,一般用在多线程下载(客户端发起)
  • Referer 当前请求从哪个地址发起
  • User-Agent 请求发起终端信息

响应首部

  • Accept-Ranges,表示服务器是否支持Range请求,支持时值为bytes,否则是none
  • Age,表示缓存到目前为止过了多久(HTTP1.0)
  • Etag,资源的唯一标识,分为强Etag和弱Etag
  • Location,用在3xx的请求中,表示客户端需要重定向到的新地址
  • WWW-Authentication/Proxy-Authentication,服务器、代理使用的认证类型
  • Server,服务器信息
  • Vary,与Vary指定首部字段同名的请求才会命中缓存

实体首部

  • Allow 允许的访问方法
  • Content-Encoding/Content-Language/Content-Length/ 内容的编码、语言、长度、类型
  • Content-Location 内容的位置,通常在和访问URI时会用到
  • Content-MD5 内容MD5编码,便于和客户端编码后进行对比,防止内容篡改
  • Content-Range 用于部分请求
  • Content-Type 文件类型,包括MIME type和字符集
  • Expires/Last-Modified 文件的过期时间和上次修改时间,用户判断缓存是否过期

除此之外,还有和Cookie相关的两个头部,它们来自网景公司对于Cookie的设计。

  • Set-Cookie,服务端下发设置Cookie信息。包含下列信息
    • expires,过期时间
    • path,适用路径
    • domain,适用域名
    • secure,限制https才会携带Cookie
    • HttpOnly,限制JS脚本访问Cookie
    • 下发的cookie内容
  • Cookie,客户端期望的cookie内容

另外还有一些常用的首部字段:

  • X-Frame-Options,规定页面在iframe中的呈现方式
    • DENY 禁止访问
    • SAMEORIGIN 仅允许同源访问
  • X-XSS-Protection,为1时开启XSS防御

不建议使用”X-“开头的方式拓展非标准首部

HTTPS简介

HTTP缺点:

  • 使用明文 -> 通信内容可以被窃听 –HTTPS–> 加密通信内容
  • 不能验证身份 -> DDoS攻击和伪装服务器、客户端身份 –HTTPS–> 证书证明身份
  • 不能验证内容完整性 -> 中间人攻击 –HTTPS–> HTTPS保证完整性

HTTPS特征:

  • 加密内容
  • 证书
  • 完整性保护

HTTPS建立在SSL连接之上,SSL建立在TCP连接上。SSL使用共享秘钥和公开秘钥加密两种方式混合加密。在秘钥确保安全的情况下,使用共享秘钥对称加密,优化速度;否则使用公开秘钥确保安全性。

  • 共享秘钥,双方使用同一秘钥加密和解密,秘钥被监听后加密就失去了意义
  • 公开秘钥,使用公开秘钥加密,使用私有秘钥解密

然而公开密钥本身并不能确保完整性,需要证书机构(CA)颁发证书认证,确保秘钥和端的有效以及合法性。服务端也可以使用OpenSSL为自己颁发自认证证书,但是一般会在浏览器上弹出警告。

HTTPS建立连接的过程包括:

  1. 协商决定秘钥组件
  2. 服务端发送公开密钥、证书
  3. 客户端检查证书合法性,以确认服务端身份,并拿到公钥
  4. 客户端发送pre-master secret随机字符串
  5. 服务端使用私钥加密pre-master secret hash值,返回加密的hash值(避免黑客尝试破解私钥)
  6. 客户端使用公钥解密hash,对比自己之前生成的pre-master secret字符串hash,若一致,及证明服务端身份的合法性
  7. 客户端生成一个对称加密算法和秘钥master-secret,使用公钥加密,发送给服务端
  8. 双方使用master-secret进行通信

通信的完整性可以通过将报文内容生成hash交由客户端验证来实现。

SSL最初由网景开发,1.0和2.0版本被发现存在问题已被废弃。3.0后由IETF接手。目前可用的协议版本有SSL3.0和TLS1.0、TLS1.1、TLS1.2,其中最常用的是SSL3.0和TLS1.0。

证书

证书包含:

  • 发布机构(CA)
  • 有效期
  • 持有者(由CA担保证明持有者身份)
  • 公钥
  • 数字签名算法
  • 指纹算法

为了保证安全,在证书的发布机构发布证书时,证书的指纹和指纹算法,都会用自己的私钥加密后再和证书放到一起发布。使用者在打开证书时,根据加密算法,系统使用自带的公钥解密指纹和指纹算法,使用指纹算法计算证书的hash值和指纹对比,如果对的上就代表证书没问题。系统使用的公钥和证书一般由证书发布机构自己生成,内嵌在操作系统中。

证书颁发机构(CA)通常会去做很多工作确保持有者的合法性,信任CA代表着信任CA颁发证书中的所有信息。所以一般系统只选择信誉较好的CA机构。公司内部使用或自生成的证书就只能被在指定范围内被信任。

身份验证

  • BASIC 使用用户名密码验证,明文传输
  • DIGEST 质询响应,防止密码被拦截,安全度和便利性都较差
  • SSL 客户端证书 + HTTPS传输,成本高
  • HTTP表单 + Cookie/Session验证

功能追加协议

WebSocket

全双工,解决Ajax,长短轮询的局限。握手过程很简单:

  • 请求方添加Upgrade首部字段,声明升级到websocket。包含Sec-WebSocket-Key,Sec-WebSocket-Protocol,Sec-WebSocket-Verison等必要字段
  • 响应方回复101状态码,包含Sec-WebSocket-Accept(是根据Sec-WebSocket-Key生成的),Sec-WebSocket-Protocol

连接建立后,双方使用WebSocket的方式进行通信

WebDAV

基于Web的文件属性管理。新增了一些方法和状态码,允许客户端远程修改服务器上的文件。

Web应用

RSS

RDF Site Summary,简易内容聚合。和Atom一样,使用XML的形式发布信息,通过特定的RSS阅读器阅读。

常见Web攻击方式

根本原因:HTTP本身没有必要的安全机制。

输出值转义相关攻击方式

  • XSS,跨站脚本攻击,主要出现在动态拼接HTML的场景中,用户恶意注入的script代码段埋下陷阱,诱导用户误操作触发。盗取用户密码或Cookie信息
  • SQL注入,通过URL注入的方式,制造恶意SQL语句,出现在动态拼接SQL语句的场景下。可以绕过认证、甚至破坏整个数据库
  • OS命令注入,类似SQL注入,出现在动态拼接OS语句的场景下。
  • HTTP首部攻击,出现在服务端响应头部使用了用户侧输入场景下,比如302响应中的Location头部可能存在的query部分。攻击者可以通过添加换行符,恶意添加新的首部字段,甚至篡改原有的响应主体
  • 邮箱首部注入攻击,类似HTTP首部攻击

类似地还有目录遍历漏洞、远程文件引用漏洞。

通过上面几种攻击方式,可以看到,永远不要信任用户侧输入使用白名单机制,禁止动态拼接用户输入的语句

设计缺陷相关攻击方式

  • 强制浏览,在服务器公开目录下,浏览开发者本非自愿公开的文件。
  • 不正确的系统错误处理方式,数据库等内部系统抛出的错误,对用户毫无帮助,反倒能让攻击者看到服务背后的一些细节。包括,数据库错误、PHP等脚本错误、Web服务器的错误
  • 开放重定向,网站有诸如?redirect=xxx的path可以重定向时,一定要对redirect后的网址进行白名单控制,防止成为钓鱼攻击的跳板

session相关

  • XSS盗取cookie,伪装用户登录
  • 发送恶意链接,强制用户使用攻击者指定的session ID
  • CSRF,跨站信息伪造,在带有用户信息的domain里留下恶意的网络请求,伪造用户发起请求,伪造请求可以通过<img src="xx" />, <video src="xxx></video>等多种形式

其他

  • 穷举法破解密码,暴力破解。使用图片验证码、手机验证码、机器检测等方式限制同IP的访问频率。
    • 彩虹表。使用salt,增加破解难度
  • 撞库。建议用户在不同域内使用不一样的密码
  • 点击劫持,使用透明元素覆盖在目标网页上。在18+网页中最常出现(😂)。
  • DoS(Denial of Service)拒绝服务攻击,构造大量合法的网络请求,导致服务器超负荷。通常都是DDoS(Distributed Denial of Service)的形式。需要在IP层去过滤攻击的IP。
  • 后门程序

原版链接: https://book.douban.com/subject/25820714/

准则

  • 减少用户思考
  • 减少用户心理负担

原因: 用户时间有限,界面必须易于理解

用户的使用方法

  • 82原则,只扫描感兴趣的
  • 用户只寻求一个可行而非最优的答案
  • 用户并不关心产品如何运作,会按照某个可用的方式一直使用下去

方法论

  • 利用习惯性思维,包括页面位置、使用方法、元素外观这些被培养起来的习惯。如无必要,勿增实体。
  • 层次分明,逻辑上的关联能从视觉上直接体现;能够划分区域
  • 明确标识可交互元素;提高信噪比,减少不必要视觉干扰
  • 标题更靠近关联的内容,突出关键词汇
  • 减少冗余文本,包括欢迎语、指示文字

Web导航

重要性:

  • 用户在web中感受不到方位
  • 用户需要更快地达成目标

习惯用法:

  • 导航部分(或是某些公用部分)固定出现在页面同样位置,会让用户能立即确认自己还处在这个网站里
    • 市场类应用里,包括站点ID、栏目、实用工具、搜索
  • 站点ID需要有独特可区分的设计
  • 一个返回首页的导航链接
  • 简洁明了的搜索框
    • 简单的按钮文案
    • 减少无用的提示文字
    • 明确可能的搜索选项(如果有的话)
  • 每个页面需要有个名字(保留意见)
    • 合适位置
    • 引人注目
    • 和链接保持尽量一致
  • 明确告诉用户“我在哪儿”
    • 面包屑
    • tab
  • 上述元素主要的原因:现实生活中,用户并不会按照设计师规划好的路径访问网页,可能会来自分享链接、搜索引擎,并不能保证从入口进入。要能让用户在任意一个页面都可以清楚明白它要完成某项任务的话,应该如何使用当前这个网页。

吸引用户时需要注意的地方

主页要能传达整体印象。必须能显而易见地直截了当地明白:

  • 这是什么网站
  • 我能在里面做什么
  • 网站里有什么
  • 为什么选择这个网站

在用户弄清楚这些问题的最初几秒甚至是最初几毫秒,是决定你能否留住他的关键(晕轮效应)。而且因为上面加粗字体的原因,你可能要在主页外的其他页面也保证这一点。

一些手段:

  • 靠近站点ID的简洁的slogan
  • 一些推介语
  • 以明确主张为目标占用空间
  • 在描述使命时保证坦诚
  • ab test和数据说话

好口号和好的站点ID一样,是非常重要的。它需要至少有下面几点特征:

  • 清晰简洁、言之有物
  • 明确产品特色与优势,最好是只有你能适用,别的产品都用不了的那种
  • 最好能再个性、俏皮一点

当然你们公司足够出名的话,上面这些就当不存在就行。

接下来的任务就是,告诉用户该从哪里开始和避免滥用首页推介。

怎样减少信仰讨论

  • 避免关于个人喜好的讨论(如:“我不喜欢下拉框”)
  • 针对场景,根据经验选择(如:“我认为这种场景下不适合下拉框”)
  • 充分测试,数据说话反哺经验

如何进行可用性测试

当下的互联网公司迭代速度之快,可能并没有时间做这方面的研究。

区分开焦点测试(类似于种子用户,听取他们的使用感受和反馈)和可用性测试。

  • 焦点测试在早期阶段
  • 可用性测试持续进行
  • 周期性(比如一个月)进行可行性测试
  • 暴露严重问题,因为团队可能并没有资源解决所有问题
  • 应该有个主持人

最有可能的测试流程:

  • 介绍部分
  • 简单的提问部分,了解测试者的背景
  • 简单的主页浏览,询问感受
  • 完成测试任务
  • 问题询问

典型的问题:

  • 用户不清楚概念
  • 用户找不到想要的字眼
  • 内容太多了

移动时代带来的挑战

  • 狭小空间的约束
    • 用户需要立即完成或经常重复的工作应该一样就能看到
    • 其他的事情应该轻点几下就能完成,而且有显而易见的路径到达
  • 兼容多平台的UI解决银弹是很难的
  • 在UI上给用户足够的按钮,比如一个有着三维样式闪着光的按钮
  • 意识到没有光标了
  • 应用最好能“让人快乐”
  • 移动应用尤其需要可学习,然后是可记忆

用户的好感度

降低好感度的几种方式

  • 隐藏用户想要的信息
  • 对用户交互不宽容
  • 询问用户过多信息
  • 敷衍用户
  • 看上去不专业

如何提升好感度

  • 知道用户想要什么
  • 简明易懂
  • 看上去花了心思
  • 知道用户的可能问题,并给予解释
  • 提高鲁棒性

如何说服你的老板推进可用性

参考:my-git/git-workflow-tutorial.md at master · xirong/my-git

git工作流有多种使用方法,在实际工作中的不良工作习惯,会造成很让人头大的麻烦。下面距离一些常用的工作流。

集中式

类似SVN,集中式工作流以中央仓库作为项目所有修改的单点实体,只用到master这一个分支。开发者提交功能修改到中央库前,采用rebase的方式“在其基础上添加自己的修改”,得到完美的线性历史;遇到冲突时,通过git statusgit add合并冲突。最后git rebase --continue即可。遇到困难无法进行下去时,git rebase --abort就可以撤回到rebase前的状态。

在这种工作流下,使用rebase参数比不使用的git pull好处在于,rebase后的提交记录会少一次累赘的“合并提交”。

功能分支

git相较SVN强大在分布式的特征。功能分支工作流主要针对新增功能集成到正式项目。功能分支工作流仍然以中央仓库为基础,但不是直接提交本地历史到各自的本地master分支,而是在开发新功能时创建新的分支,描述新功能。不同的功能分支相互隔离,同时也保证master分支的代码一定没有问题。一旦功能分支push到master,意味着功能与其他开发者共享。

合并到master分支的过程通过创建pull request进行,在pull request请求中,让其他开发者有机会先去review变更。Pull request被接受后,剩下的工作就和集中式很像了,拉取master分支代码,合并,提交。

工作流程上:

  1. 先checkout功能分支
  2. 做本地开发提交,以及push -u推送到远端分支(-u是跟踪远端对应分支的意思)
  3. 完成开发后,提交pull request,请求合并远端功能分支到master,团队其他成员可以进行评论
  4. 在接受前,团队所有成员有需要,可以提交自己的修改到该功能分支,也会显示在pull request里
  5. 在pull-request被接受后,在本地master上可以用pull或者pull -r的方式合并功能分支,前者更像功能和原来代码的合并,后者更偏向线型的提交历史

gitflow

Gitflow工作流通过为功能开发、发布准备和维护分配独立的分支,让发布迭代过程更流畅。相较功能分支更复杂,但也更健壮。仍然用中央仓库作为所有开发者的交互中心。相对于使用仅有的一个master分支,Gitflow工作流使用两个分支来记录项目的历史。master分支存储了正式发布的历史,而develop分支作为功能的集成分支。从而可以在master的所有提交附上版本号

每个新功能位于一个自己的分支,有着和功能分支一样的开发工作流,唯一不同的是,功能分支不是从master分支上拉出新分支,而是使用develop分支作为父分支。每次合并都位于develop分支。

一旦develop分支上有了做一次发布(或者说快到了既定的发布日)的足够功能,就从develop分支上checkout一个发布分支release。从这个时间点开始之后新的功能不能再加到这个分支上——这个分支只应该做Bug修复、文档生成和其它面向发布任务。在release工作完成后,合并release分支到master,并加上tag。同时,release上做的修改要合并会develop分支。最后删除release分支。

维护分支或说是热修复(hotfix)分支用于给产品发布版本(production releases)快速生成补丁,这是唯一可以直接从master分支fork出来的分支。修改完成后,修改应该立马合并回master和develop。master也应该为合并生成新的tag。

forking

Forking工作流是分布式工作流,可以安全可靠地管理大团队的开发者(developer)和不信任贡献者(contributor)的提交。这种工作流不是使用单个服务端仓库作为『中央』代码基线,而让各个开发者都有一个服务端仓库。这意味着各个代码贡献者有2个Git仓库而不是1个:一个本地私有的,另一个服务端公开的。Forking工作流的一个主要优势是,贡献的代码可以被集成,而不需要所有人都能push代码到仅有的中央仓库中。开发者push到自己的服务端仓库,而只有项目维护者才能push到正式仓库。

新开发者想要在项目上工作时,不是直接从正式仓库克隆,而是fork正式项目在服务器上创建一个拷贝。这个仓库拷贝作为他个人公开仓库 —— 其它开发者不允许push到这个仓库,但可以pull下来修改。要提交本地修改时,push提交到自己公开仓库中 —— 而不是正式仓库中。 然后,给正式仓库发起一个pull request,让项目维护者知道有更新已经准备好可以集成了。为了集成功能到正式代码库,维护者pull贡献者的变更到自己的本地仓库中,检查变更以确保不会让项目出错, 合并变更到自己本地的master分支, 然后push master分支到服务器的正式仓库中。到此,贡献的提交成为了项目的一部分,其它的开发者应该执行pull操作与正式仓库同步自己本地仓库。

具体来说,大致有下面几步:

  1. 开发者fork正式仓库
  2. 开发者clone自己的fork出来的仓库,与之前工作流不一样的是,Forking工作流需要2个远程别名 —— 一个指向正式仓库,另一个指向开发者自己的服务端仓库。,像下面这样
    1
    git remote add upstream https://bitbucket.org/maintainer/repo
  3. 开发者修改都是私有的,如果项目往前走了,可以用git pull获得新的提交
  4. 开发者准备分享新功能时,需要先push到自己的公开仓库中,然后发起pull request通知项目维护者,集成开发者的功能分支
  5. 项目维护者通过GUI岔开pull request或者pull代码到自己的本地仓库,再手动合并。
  6. 开发者通过pull upstream master的方式拉取项目最新进展

pull request

pull request用于合并不同分支或不同仓库的代码,并在合并前进行一些讨论和代码微调,在上面不同工作流的情况下具体功能体现也不同。

上面几种工作流范式只是几种标准的建议,正式的项目版本管理中,可以糅合上面的一些特点。

git case sensitive

git本身是大小写敏感的。但在大小写不敏感的系统里,需要用hack方法记录仅修改文件名大小写的改动。

1
2
3
git mv file.txt temp.txt
git mv temp.txt File.txt
git commit -m "Renamed file.txt to File.txt"

webpack的一些经验

DefinePlugin

允许创建一个在编译时可以配置的全局常量。在构建区分环境的包时很有用。

1
2
3
4
5
6
7
new webpack.DefinePlugin({
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify("5fa3b9"),
BROWSER_SUPPORTS_HTML5: true,
TWO: "1+1",
"typeof window": JSON.stringify("object")
})

注意:这个插件直接执行文本替换。因此:

  • 如果这个值是一个字符串,它会被当作一个代码片段来使用。
  • 如果这个值不是字符串,它会被转化为字符串(包括函数)。
  • 如果这个值是一个对象,它所有的 key 会被同样的方式定义。
  • 如果在一个 key 前面加了 typeof,它会被定义为 typeof 调用

resolve alias

创建import或require的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的常用模块:

1
2
3
4
5
alias: {
@: path.resolve(__dirname, 'src/'),
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}

z-index可能的坑

使用前提:z-index只能在position属性值为relative或absolute或fixed的元素上有效。

z-index值只决定同一父元素中的同级子元素的堆叠顺序。父元素的z-index值(如果有)为子元素定义了堆叠顺序(css版堆叠“拼爹”)。向上追溯找不到含有z-index值的父元素的情况下,则可以视为自由的z-index元素,它可以与父元素的同级兄弟定位元素或其他自由的定位元素来比较z-index的值,决定其堆叠顺序。同级元素的z-index值如果相同,则堆叠顺序由元素在文档中的先后位置决定,后出现的会在上面。

git submodule

参考:GIT 子模块

最新一个项目里要复用已有的一个git库的代码,具体来说就是要将之前在WebView的内容复刻到PC版完成(这个需求貌似应该还挺常见的)。为了保证代码复用性,选择了git submodule的方法。这也是我此前从没用过的一个命令。

简单来说,是一个 GIT 仓库下面某个文件夹的来源可以跟本库的来源不同,这个文件夹连接着别的库,由别的库负责按本控制和管理。是不是和npm包管理的形式比较像。子模块可以手动添加,也可以在克隆一个主库的时候就直接实体化。具体来说,有四种情况:

  • 克隆库的时候要初始化子模块 => 加上--recursive参数 git clone --recursive git@github.com:shenlvmeng/trace-maker.git
  • 初始化已有库的子模块 => git submodule update --init --recursive
  • 从子模块的源更新该子模块 => git submodule update --recursive --remote
  • 添加一个新的子模块 => git submodule add <git address> <folder address>

已有有git submodule的库内,.gitmodules是下面的样子:

1
2
3
[submodule "wheel"]
path = wheel
url = git@github.com:shenlvmeng/wheel.git

npm install

npm install后跟的绝不仅仅只是包名,还可以通过ssh、http的形式引入npm包,唯一的要求是有package.json

1
2
3
4
5
6
7
8
9
10
11
12
npm install (with no args, in package dir)
npm install [<@scope>/]<name>
npm install [<@scope>/]<name>@<tag>
npm install [<@scope>/]<name>@<version>
npm install [<@scope>/]<name>@<version range>
npm install <git-host>:<git-user>/<repo-name>
npm install <git repo url>
npm install <tarball file>
npm install <tarball url>
npm install <folder>

alias: npm i

一个package可以是下面的形式:

  1. 包含package.json的工程文件夹
  2. gzip过的“1”的压缩包
  3. 指向“2”的url
  4. 发布在npm-registry的<name>@<registry>字符串
  5. 发布在npm-registry的<name>@<tag>字符串
  6. 发布在npm-registry的<name>字符串(最新版本)
  7. 一个指向“1”的合法git地址

cleave.js

一个自动格式化输入框的工具,有npm包、script标签等几种引用形式,还有react的使用方式。

地址:Format your <input/> content when you are typing

object-fit & object-position

这两个CSS属性分别用于指定替换元素在其盒模型内的覆盖大小和对齐方式。使用效果很类似background-sizebackground-position。替换元素即内容不受CSS视觉格式化控制的元素,如image、iframe、video、textarea等。

这使得本来自己决定模型大小的元素可以受CSS控制决定位置排布和大小。在需要自适应元素大小的场景下很好用,比如用户头像展示等。

唯一的小小缺憾可能是IE11还不支持这两个属性,以及Edge只支持对<img>使用。

移动端触摸默认行为优化

  • user-select: none 禁止用户选择
  • -webkit-touch-callout: none 防止长按contextmenu弹出。类似的还有contextmenu事件里的e.preventDefault()
  • -webkit-tap-highlight-color: transparent 删除可点击元素默认的黑影

上传进度条

利用xhr事件的onprogress事件。

1
2
3
4
5
6
7
8
9
10
11
xhr.onprogress = function (e) {
if (e.lengthComputable) {
console.log(e.loaded+ " / " + e.total)
}
}
xhr.onloadstart = function (e) {
console.log("start")
}
xhr.onloadend = function (e) {
console.log("end")
}

不显示滚动条

基于Webkit的浏览器,可以使用CSS的方式隐藏滚动条。

1
2
3
4
5
&::-webkit-scrollbar {
width: 0;
height: 0;
background: transparent;
}

keyup无法prevent default

keyup fires after the default action.

keydown and keypress are where you can prevent the default.
If those aren’t stopped, then the default happens and keyup is fired.

来源:jquery - javascript prevent default for keyup - StackOverflow

mixin in react

版本16之前,可以用mixin特性。16之后使用高阶组件HOC + ES6 class语法实现。参考

user-select在Edge浏览器下的适配问题

设置user-selectnone在Edge浏览器下会导致input无法输入内容。可以用下面的写法,避免对input标签应用该属性。

1
2
3
*:not(input) {
user-select: none;
}

参考:html - Can’t type in input field using Microsoft Edge and Safari - StackOverflow

浏览器跨tab通信

最近业务遇到了一个需求:同一浏览器上多tab用户信息同步的问题,所有这个域名下的需要强制一样的用户信息,避免困惑。

跨tab通信主流方案有两种:

  • localStorage,利用window的storage事件,传递信息
  • BroadcastChannel,新的API,通过postMessageonMessage完成双向通讯
1
2
3
var bc = new BroadcastChannel('test_channel');
bc.postMessage('This is a test message.'); /* send */
bc.onmessage = function (ev) { console.log(ev); } /* receive */

后者还未得到广泛支持,需要前者进行polyfill。

aos

Animation on scroll。michalsnik/aos at master · Animate on scroll library.元素滚动至中的CSS动画,适合实现官网、落地页等效果。

extract-text-webpack-plugin

抽出CSS/Less/Sass等样式作为单独文件,用于那些需要提前加载样式的页面。详细用法见github

坑:

  1. 不支持webpack4.x,报内部错误(2018/07/30) => 使用@next下载最新版
  2. 报错Module build failed: ReferenceError: window is not defined => style-loader在extract-text-webpack-plugin中只做fallback项使用,见issue#503

常见调试技巧

  • 代码中插入debugger可以在该位置触发断点调试
  • console.dir可以打印对象结构,大多数情况和console.log表现一致,在document等DOM元素上表现不同

react组件复用设计思路

  • 当设计的组件为自闭型时,通过传入数据(不要传入功能)props的方式定制组件
  • 当设计的组件在有些场景下需要外部传入功能才能完整时,使用继承的方式实现
  • 在可以拆分出原子组件,且有此必要的时候,使用原子组件拼装业务组件
  • HOC优于mixin

前端科技树探索之路

前端的涵盖范畴是和客户直接交互的部分。

以下几个因素促进了前端在这些年差异化成一个需要专业人才的领域

  • Web API不断丰富和更新,允许JS做更多的事情,同时也需要不停学习跟进
  • 语言规范赋予JS更多的特性和可能,允许专业的人做更专业的事
  • Node等轮子的出现拓展了JS的应用场景,方向更加细化
  • 用户对界面要求越来越高,需要专门的人处理

从而使前端渐渐分化出来成为一个面向复杂场景、承诺服务质量、进入工程领域的职业。

更细化的说,面向复杂场景包括:

  • 浏览器应用、桌面应用、移动端应用、后端应用多宿主
  • 复杂的网络环境
  • 差异化巨大的浏览器和浏览器版本(所幸比以前好了很多)
  • 用户群体的不同
  • ……

承诺服务质量包括:

  • 更快地渲染页面
  • 更美观的页面效果
  • 更流畅的用户交互体验
  • 更高的代码稳定性(对应着lint和debug能力)
  • 差异化环境的表现一致性
  • ……

进入工程领域包括:

  • 更舒适的开发体验(设计模式与诸多轮子)
  • 更高的开发效率(如工作流的设计)
  • 更顺滑的团队间协作(如mock)
  • 版本控制
  • ……

上面是作为一个技术的要求,在公司应用范畴,还需要考虑下面这些:

  • 产品设计

  • 团队建设

  • 人才培养

  • 项目管理

  • 立身之本

    • HTML
    • DOM
    • JavaScript基本语法
    • CSS
  • 关联技术

    • Web API
    • ajax
    • JSON
    • 正则
    • SVG/Canvas/WebGL
    • PWA
  • 深入了解

    • ES6 ES7
    • TypeScript
    • CSS3
    • SASS Less
  • 现有轮子

    • NodeJS
    • Electron
    • React
0%