0%

HTTP提供匿名、无状态的请求/响应 服务,为了给用户个性化的服务,有必要识别用户,主要的方式有:

  • HTTP首部承载用户身份信息

    HTTP请求首部有From (用户的email地址)、user-agent(用户的浏览器软件)、Referer(用户是从这个页面跳转过去的)、Authorization(用户名和密码)等字段,利用这些字段可以识别用户。

以下是首部承载的信息:

首部承载的信息

  • 跟踪客户端IP地址,通过IP地址识别用户。

    IP识别有弊端,(1)它识别的是及其,不是用户 (2)网络服务提供商可能会提供动态的IP (3)如果使用了代理,那获取到的IP可能只是代理的IP.
    (4)为了安全,用户可能通过网络地址转换(Network Address Translation, NAT) 防火墙来浏览网络内容,这些NAT设备隐藏了防火墙后面的那些实际客户端的IP。

  • 用户登录,用认证方式识别用户。

    如果服务器希望在为用户提供对站点的访问前先登录,则可以返回 401 Login Required ,然后浏览器会弹出登录框。这样就能显式地询问用户是谁。

  • 胖UTL,在URL中嵌入识别信息的技术

    有些web站点会为每个用户生成特定版本的URL来追踪身份,用户浏览站点时,web服务器会动态生成一些超链,继续维护URL中的信息。但是,这种方案有几点问题:

  1. 无法共享URL,包含了特定用户的信息,如果分享出去,无意中将积累的个人信息共享出去了
  2. 需要对每个用户动态生成胖URL,额外的服务器负荷
  3. 破坏缓存。为每个URL生成用户特有的版本,意味着不再有供公共访问的URL缓存了。
  • cookie

    是目前识别用户,实现持久会话的最好方式。包括 会话cookie 和 持久cookie ,他们之间的唯一区别就是他们的过期时间。浏览器会记住从服务器返回的set-cookies或者set-cookie2首部中的cookie内容,并将cookie存储在cookie数据库,将来用户访问同一站点时,浏览器会按照某些规则将cookie放在
    cookie请求首部中将其传回去。

以下是为用户设置cookie的情形:

为用户设置cookie

cookie的域属性:

产生cookie的服务器可以向set-cookie响应首部添加一个Domain属性来控制哪些站点可以看到那个cookie,比如,下面的HTTP响应首部告知浏览器将 cookie user=”haha” 发送给域 “.baidu.com”中的所有站点:

set-cookie: user=”haha”;domain=”baidu.com”

如果访问的是www.baidu.com 、news.baidu.com 或其他任何以 .baidu.com 结尾的站点,下列的cookie都会被发布出去;

Cookie :user=”haha”

cookie 规范甚至允许用户将cookie域部分web站点关联起来,可以通过path属性来实现:

例如,某个web服务器可能是由两个组织共享的,每个组织都有独立的cookie,站点 www.baidu.com 可能会将部分web站点用于外卖,如 www.baidu.com/waimai/ ,可以用一个独立的cookie来记录用户喜欢的外卖口味,如:

Set-cookie: taste=hot; domain=”baidu.com”; path=/waimai/

如果用户访问 http://www.baidu.com/waimai/bj/index.html 时就会获得两个cookie:

Cookie: user=”haha”
Cookie: taste=”hot”

因此,可以理解为:cookie就是由服务器贴到客户端上,由客户端维护的状态片段,只会回送给那些合适的站点。

我们有Set-Cookie 和 Set-Cookie2 两种,后者属于更新的版本。Cookie2首部告知服务器,用户Agent代理理解新形势的cookie,病提供了所支持的cookie标准版本,:
Cookie2: $Version=”1”
如果服务器理解新形式的cookie,就能识别出Cookie2首部,并在响应首部发送Set-Cookie2(而不是Set-Cookie),如果客户端从同一个响应中既获得了Set-Cookie 首部又获得了 Set-cookie2首部,就会忽略老的 Set-cookie首部。

TCP连接

HTTP的连接实际上就是TCP的连接和一些使用连接的规则。

TCP是可靠的数据管道:TCP为HTTP提供了一条可靠的比特传输管道,从TCP连接一端输入的字节会从另一端以原有顺序、正确地传送出来。

TCP流是分段的,由IP分组传送:HTTP以流的形式将报文数据通过一条打开的TCP连接传输,TCP会将数据流分成若干段,每个TCP段都是由IP分组承载,从一个IP地址发送到另一个IP地址。

任意时刻计算机都可以有多条TCP连接处于打开状态,TCP是通过端口号来保持这些连接的正确运行。

TCP的连接是通过4个值来识别的:<源IP地址、源端口号、目的IP地址、目的端口号> ,这4个值定义了唯一一条连接,IP地址可以将你连接到正确地计算机,而端口号可以将你连接到正确的应用程序。

以下表示四条不同的TCP连接,各连接要么源IP不同,要么目的IP不同,要么源端口不同,要么目的端口不同:

四条不同的TCP连接

利用套接字操纵TCP客户端和服务器之间的连接:

http通过tcp发送数据的过程

HTTP性能讨论

性能概述

HTTP事务流程主要包括几个方面:

  1. 客户端首先根据URI确定WEB服务器的IP和端口,如果没有DNS缓存的话,这个过程可能花费数十秒。
  2. 接下来,客户端向服务器发送TCP连接请求,并等待服务器应答,每条新的TCP连接都会有连接建立时延。
  3. 一旦连接建立起来,服务器处理请求、因特网传输请求报文都需要时间。

HTTP位于TCP上层,所以HTTP事务的性能很大程度上取决于TCP通道的性能。这其中,对HTTP性能影响最常见的是TCP相关的时延,包括:

  • TCP连接建立握手

    小的HTTP事务可能会在TCP建立上花费50%的时间,这是不合理的。

  • 用于捎带确认的TCP延迟确认算法

    每个TCP段都有一个序列号和数据完整性校验和,每个段的接收者收到完好的段时,都会向发送者回送确认分组。如果发送者没有在指定的时间窗口收到确认信息,发送者就认为分组已损坏,并重新发送数据。由于确认报文很小,所以TCP允许TCP将返回的确认信息与输出的数据分组结合在一起,可以更有效地利用网络。为了增加确认报文找到输出数据分组的可能性,很多TCP栈都实现了一种“延迟确认”算法,延迟确认算法会在一个特定的窗口时间(通常100~200毫秒)内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组,如果那个时间段内没有输出数据分组,就将确认信息放在单独的分组中传送。

  • TCP慢启动拥塞(se)控制

    TCP数据传输的性能还取决于TCP连接的使用期(age)。TCP连接会随着时间进行自我“调谐”——期初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输速度,这种“调谐”称为 TCP慢启动,用于防止因特网的突然过载和拥塞。例如,如果HTTP事务有大量的数据要发送,是不能一次将所有分组发送出去的,必须发送一个分组等待确认,然后可以发送两个分组,每个分组都必须确认,这样就可以发送四个分组了,这种方式被称为“打开拥塞窗口”。由于存在这种拥塞控制,所以新连接的传输速度会比已经传输过一定量数据的“已调谐”的连接慢一些。由于已“调谐”的连接快,因此HTTP中有一些可以重用现存连接的工具,提高效率。

  • 数据聚集的Nagle算法与TCP_NODELAY

    如果每次发送的数据量很少,但是传输的次数很多,就会产生大量包含少量数据的分组,网络性能就会下降,Nagle算法鼓励发送全尺寸(LAN上最大尺寸的分组大约1500字节,因特网上是几百字节)的段,试图在发送一个分组前,将大量TCP数据绑在一起,提高网络效率,毕竟每个TCP段中哪怕只放了一个字节,也至少装载了40个字节的标记和首部。但是这也会引发HTTP性能问题,首先,可能某个小的HTTP报文无法填满一个分组,但等待那些永远不会到来的额外数据而产生时延。其次,Nagle算法与前面体积的延迟确认似乎是矛盾的 —— Nagle算法会阻止数据发送,直到有确认分组抵达为止,但是确认分组会被延迟确认算法延迟100~200毫秒。

  • TIME_WAIT时延和端口耗尽

    当某个TCP端点关闭TCP连接时,会在内存中维护一个小的控制块,用来记录最近所关闭连接的IP地址和端口号,这类信息指挥维持一小段时间,通常是所估计的最大分段使用期的2倍(称为2MSL,通常为2分钟)。

HTTP的性能改善

有几种方法可以提高HTTP的性能:

  1. 并行连接,通过发起多条TCP连接发起并发的HTTP请求。这样可以避免单条连接的空载时间和没有充分利用带宽。以下两个图为对比:
    串行:
    串行

并行:
并行
2. 持久连接,用于消除连接及关闭的时延。 以前使用 keep-alive 字段,现在使用 persistent。
3. 管道化连接。通常,http请求总是顺序发送的,下一个请求只有在当前请求的响应被完全接受的时候才会被发送。由于网络延迟和带宽的限制,这样会导致在服务器发送下一个响应的时候中间有很大的延迟。管道化连接可以将多条连接放入队列,当第一条请求发出之后,第二条第三条请求也可以开始发送了,这样做可以降低网络环回时间,提高性能。

如果一个事务,不管是执行一次还是很多次,得到的结果都是相同的,那我们说这个事务是幂等的。 GET、HEAD PUT DELETE TRACE OPTIONS 是幂等的,但POST不是幂等的,所以不应该以管道化的方式发送POST请求。

书本之外:关于TIME_WAIT

以下内容参考自博客:

https://blog.csdn.net/u013616945/article/details/77510925

描述

首先调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就说该发送方会保持2MSL时间之后才会回到初始状态。MSL值得是数据包在网络中的最大生存时间。产生这种结果使得这个TCP连接在2MSL连接等待期间,定义这个连接的四元组(客户端IP地址和端口,服务端IP地址和端口号)不能被使用。

产生的原因

  • 为实现TCP全双工连接的可靠释放

假设发起主动关闭的一方(client)最后发送的ACK在网络中丢失,由于TCP协议的重传机制,执行被动关闭的一方(server)将会重发其FIN,在该FIN到达client之前,client必须维护这条连接状态,也就说这条TCP连接所对应的资源(client方的local_ip,local_port)不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。如果主动关闭一方不维护这样一个TIME_WAIT状态,那么当被动关闭一方重发的FIN到达时,主动关闭一方的TCP传输层会用RST包响应对方,这会被对方认为是有错误发生,然而这事实上只是正常的关闭连接过程,并非异常。

  • 为使旧的数据包在网络因过期而消失

    为说明这个问题,我们先假设TCP协议中不存在TIME_WAIT状态的限制,再假设当前有一条TCP连接:(local_ip, local_port, remote_ip,remote_port),因某些原因,我们先关闭,接着很快以相同的四元组建立一条新连接。本文前面介绍过,TCP连接由四元组唯一标识,因此,在我们假设的情况中,TCP协议栈是无法区分前后两条TCP连接的不同的,在它看来,这根本就是同一条连接,中间先释放再建立的过程对其来说是“感知”不到的。这样就可能发生这样的情况:前一条TCP连接由local peer发送的数据到达remote peer后,会被该remot peer的TCP传输层当做当前TCP连接的正常数据接收并向上传递至应用层(而事实上,在我们假设的场景下,这些旧数据到达remote peer前,旧连接已断开且一条由相同四元组构成的新TCP连接已建立,因此,这些旧数据是不应该被向上传递至应用层的),从而引起数据错乱进而导致各种无法预知的诡异现象。作为一种可靠的传输协议,TCP必须在协议层面考虑并避免这种情况的发生,这正是TIME_WAIT状态存在的第2个原因。

time_wait状态如何避免

首先服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。在一个非常有用的场景就是,如果你的服务器程序停止后想立即重启,而新的套接字依旧希望使用同一端口,此时SO_REUSEADDR选项就可以避免TIME_WAIT状态。

最近打算开始写点东西,发出来,一来可以督促自己持续地将所学所感悟的东西记录下来,二来,以前一直在自己遇到问题解决不了的时候去google,获取他人的答疑解惑,而自己写的总结性的东西都在有道云笔记上(主要怕误导大家),这次重新搭建自己的博客,附上了评论系统,所以希望即使写出来的东西不完善也能让大家留个评论,能够及时改正,因此就膨胀发出来了。同时希望这个教程能够帮到一些人亲手搭建自己的博客。

根据一直以来的经验,使用第三方框架之前一定要仔细阅读官方的文档,先不要去获取网上所谓的教程,因为每个教程里面针对的 操作系统、搭设的环境等 不一定和你的一模一样,而官方文档一般是能涵盖你所碰到的大多数问题的

先放上官方的(语言可以选择中文的哦):

hexo的主页在这里:https://hexo.io/

hexo的文档在这里:https://hexo.io/docs/

如果你自己能看文档解决,那是再好不过了,如果根据官方文档踩到坑跳不出来,可以参考参考以下的教程。

一、安装nodejs 与 npm

首先声明,博主目前主要使用Ubuntu进行Android开发,然后进行一些简单的日常使用,对Ubuntu玩得并非很6,看到hexo官网上说要先安装nodejs和npm,首先想到的是去nodejs官网,但是下载下来解压之后,一脸懵逼,不知道怎么操作了。官网上没有很直观的文档(是不仔细找还不好发现),google 上也是众说纷纭,遂又硬着头皮去官网上找找解决方法,我最后找到的官方指引,点击这里就是,有针对各种系统安装nodejs的说明(同时会自动安装 npm),为了节约大家去看文档的时间,以下还是列出ubuntu环境下nodejs的安装过程:

在终端输入:

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -

注:在写本教程的时候,最新的LTS版本的nodejs是 8.11.1,所以我这里是8.x,这个版本号可以依据自己需要的版本而改动

当然,如果提示你还未安装curl,则使用以下命令安装即可:

$ sudo apt-get install curl

完成之后,再在终端输入:

$ sudo apt-get install -y nodejs

最后,输入以下命令检测是否安装成功 :

$ nodejs -v

v8.11.1

$ npm -v

5.6.0

如果显示这些版本号,说明安装成功。

二、安装hexo

根据hexo的官方介绍,里面很详细地介绍了安装过程:

1、安装hexo(如果提示权限问题请在命令前加上 sudo)

$ npm install -g hexo-cli

2、初始化hexo

在终端cd到你想要存放blog的目录,执行

$ hexo init BLOG

这行命令会帮你创建一个BLOG文件夹,并且做一些初始化操作,这里BLOG是你想要新建的存放hexo必要文件的文件夹。

3、安装依赖

$ cd BLOG

$ npm install

三、配置github

申请github账号,并且在本地电脑上安装git ,并且将本地生成的公钥更新到github上,以便本机有权限将生成的静态网页push到github服务器。
参考附件:github官方提供的ssh设定:https://help.github.com/articles/connecting-to-github-with-ssh/

在github上新建project

在github上新建project ,只需要注意project的名字一定得是 username.github.io 就行了,像我的博客地址是 glassx.github.io,因此我的project的名字是 glassx.github.io 。

四、配置hexo 以及 关联hexo与github

在正式写作之前,我们需要配置hexo,并且将hexo与github关联起来。

主题配置

首先是选择 主题(theme),当然也可以使用hexo的默认主题,我目前使用的是yilia主题,这个纯属个人爱好,你可以去知乎上搜索好看的hexo主题,也能从我认为的hexo主题大全中选择你中意的主题。只需将下载好的主题放到 *BLOG/themes/ *目录下备用。

用yilia主题的话,别忘了在BLOG目录下终端执行:

$ npm i hexo-generator-json-content –save

修改hexo的配置文件

打开 ** BLOG/ 目录下的 **_config.yml 文件,找到 theme 字段,将它的值改成你需要的主题名称,比如我的就是 :

theme: yilia

除此之外,还需要找到 deploy 字段,将它下面的字段配置成类似于:

deploy:
  type: git
  repository: https://github.com/glassx/glassx.github.io.git
  branch: master

https://github.com/glassx/glassx.github.io.git 换成你自己的就好了(其实这里整个就是你前面在github上新建的仓库的地址)。

安装必要控件

使用以下命令安装deploy的git工具:

$ npm install hexo-deployer-git –save

如果不安装,在部署的时候会报错: ERROR Deployer not found: git

注意:一定要在第三步的时候将你的公钥上传到github上去,也就是第三步中的 github提供的ssh设定 那个部分,否则在部署的时候会提示没有权限

五、开始写作

准备工作终于做完了,开始发挥吧!
首先新建博文:

在终端里定位到上述的BLOG文件夹下,执行

$ hexo new post “firstpage”

之后会在 BLOG/source/_post/ 目录下生成 firstpage.md 文件,编辑firstpage.md 文件,注意该文件的编辑使用的是 markdown 语法,如果不懂这个语法的话,就去google一下吧,语法很简单。

关于Ubuntu下的编辑器,我目前在使用的是 Remarkable,个人觉得挺好用,因此也安利一波。

编辑完成之后,终端中定位到 BLOG/ 目录,使用hexo命令生成静态文件:

$ hexo generate

生成静态文件命令也可以直接简化成:

$ hexo g

生成静态文件的过程就是将markdown文件 firstpage.md导出成index.html之类的静态文件,静态文件生成之后,便只需要部署了:

$ hexo deploy

同样,部署命令也可以简化成:

hexo d

部署过程实际上是将静态文件push到github指定仓库的过程,期间需要输入你的github的username,比如我的就是glassx ,之后回车;再提示你输入github登录密码(输入密码是看不见的,输入了看不见不要慌),输完回车就OK了。

当然你可以做到一行命令生成静态文件后自动部署:

$ hexo generate –deploy

或者

$ hexo deploy –generate

二者的效果是一样的,都是生成静态文件后自动部署。

部署成功之后,就可以通过 username.github.io 访问你的页面了(username换成你的名字,比如我的就是 glassx.github.io)

总结一下,在整个过程中,hexo的安装按照官方给出的步骤一步步执行就可以了,nodejs的安装也不困难,建立的github仓库其实就是为了存放静态页面,只有在deploy的时候将静态文件推送上去,当然,github提供的page功能会将你的静态页面展示出来。

建议:为了能够在不同的平台上方便地更新博客,并且防止系统损坏等意外导致博客丢失,建议在github上另外建立一个仓库,用于存放BLOG文件夹的内容

可能遇到的问题

目前很多人选择在国内搭建博客了,因为github的访问速度比较慢,这里推荐使用 gitee.com 。

如果使用过程中,每次 hexo g -d 都需要输入账号密码,那么我们可以通过以下步骤来实现免输入账号密码:

  1. 在 gitee 配置这台电脑的 ssh 公钥, 可以用命令验证: ssh -T git@Gitee.com
  2. 修改博客git远程提交地址: git remote set-url origin git@gitee.com:xxx/xxx.git
  3. 修改 hexo 根目录下 _config.yml 中远程仓库的地址: repository: git@gitee.com:xxx/xxx.git

更多的博客装修内容可以参考:https://blog.csdn.net/weidong_y/article/details/90904781