-
Notifications
You must be signed in to change notification settings - Fork 5
/
content.json
1 lines (1 loc) · 125 KB
/
content.json
1
{"pages":[],"posts":[{"title":"莫泊桑短篇小说简评","text":"品味莫泊桑批判式的人(虚荣和拜金)、社会形态和战争,亦品味莫泊桑赞颂式的自然和劳动人民(正直、淳朴和宽厚)。 泰利埃公馆小说集泰利埃公馆故事讲述了一个太太在丈夫死去之后经营着一个公馆,同时在这所小公馆中工作的还有五个性格各异的妇女典型代表。每晚年轻人都会像去泡咖啡馆一样来此消遣。某天太太的弟弟写信指望她回去参加自己女儿年满十二岁的领圣体仪式,由于太太在小女孩受洗时当过教母,并且和弟弟年老的父母都已经去世,因此她接受了这个邀请。太太不放心五个姑娘(互相之间可能会爆发积怨宿恨)于是就带上了所有的人。故事比较精彩的第一个点是太太走后年轻人们因为得不到消遣的地方,而互相爆发埋怨情绪和打斗行为。故事第二个比较精彩的点是在火车上对于各阶层人物的描写,描写了商人的唯利是图,农民的憨厚淳朴以及女人们之间作祟的虚荣心。故事第三个精彩的点是对于乡下油然而生的返璞归真的田野自然体验的描写,那种令人舒适的氛围使人熏醉。故事第四个精彩的点是小女孩参加领圣体时大家所被传染的一种悲伤的气氛,惊奇的是莫泊桑并非信教人士,但是他对这一段的描写尤为神圣(个人觉得更具讽刺意义)。巴黎的肮脏的生活和乡下淳朴的环境对比,透露出作者对于乡下自然生活的向往,对于淳朴的劳动人民的欣赏,对于巴黎糜烂生活的厌恶。 男的是一个上了年纪的农民,穿一件蓝罩衫,领子打裥,宽大的袖子绣着小白花纹,在腕部束紧。他头上戴一顶老式的大礼帽,褪色发红的绒毛像刺猬毛似的竖立着。他一只手拿着一把大绿伞,一只手拎着一个大篮子。篮子里装着三只鸭,露出神色惊慌的脑袋。女的是乡下人打扮,身体僵直。她长了一张母鸡脸,鼻子尖得像鸡嘴。她在她丈夫对面坐下,发现自己处在这样一群漂亮时髦的人中间,大吃一惊,连动也不敢动。 用鸭子拟人的手法衬托了劳动人民的淳朴。 绿油油的田野在大路两边延伸,到处都夹着一大片一大片黄澄澄的油菜花,起伏不定,升起了一股强烈的、有益健康的气味,一股刺鼻的、甜津津的气味,被风送到很远很远的地方。 关于油菜花的描绘,令人身临其境。 那些姑娘已经过惯了妓院里喧闹的夜生活,乡村沉睡后的这种沉寂使她们感到很不自在。她们身上一阵颤栗,并不是因为冷,而是因为孤独,从惊慌不安的内心深处发出的孤独的颤栗。 关于人性的描写,莫泊桑总能描绘的惟妙惟肖。 公墓里的妓女故事是一个特别喜欢窥探巴黎人事物的主人公以倒叙的形式讲述的一段亲生经历,该主人公是富有的上流社会人士,且是一个不浪荡的独身者,富有才智,但是没有深度,知识多样,但并不渊博,善于领会,但不作深入研究。他喜欢公墓,觉得公墓可以使他得到休息,使他心情忧郁(他生性开朗),当然也有他思念的人在里面(曾经发疯般深爱于他的一个情妇并使他感到痛苦和懊悔)。于是在九月中旬这个阳光明媚、气候温暖的日子里,他忽然念头一转想去公墓转转,去对他已故的女朋友最后的归宿地献上他最诚挚的哀思。但是恰巧遇到了一个穿黑衣服、戴重孝的妇女,她黑纱向上翻起,脸蛋非常漂亮,她看起来痛苦得深沉,姿态僵硬,本人就像一个怀念一个男亡人的女亡人。于是主人公作为绅士很礼貌的对于她进行了一番问候,得知她的丈夫海军陆战队上尉不久前阵亡于东京时感动的热泪盈眶,之后就显得格外殷勤,但是却被这个看起来令人怜悯的女人一步步引诱了,之后这个坟墓间建立的关系维持了三个星期左右,他离开了这个令他厌倦了的女人去追求别的温情。大概一个月之后,主人公不知出于什么原因想象能在公墓里重新见到她,于是他又去了那个公墓,但是令他目瞪口呆的是他看到了这个女的以同样的方式引诱着一个风度翩翩、高贵气派、戴着荣誉勋位勋章的中年军官。 莫泊桑在讲述这个女人的时候看起来这个女人是显得多么的得体和高尚,但是事实上她只是利用男人对于逝去女人的怀念之情而复燃他们对于旧情的怀念感,这是一件很讽刺的事,也说明某些人虽然看起来道德高尚,但是事实上却是俗不可耐。 秋天的景象,那种使人感到树叶枯萎、阳光疲软无力的温热潮湿的感觉,在赋予诗意的同时,加剧了人的孤独感以及弥漫在这个地方的人类最终归宿的死亡气息。 就在我要离去的时候,我看到一个穿黑衣服、戴重孝的妇女跪在旁边一个坟墓前。她的黑纱向上翻起,露出一张漂亮的脸蛋,在她帽饰的阴影里,一卷卷淡黄色的头发仿佛被金色的曙光照得闪闪发亮,我站定了。毋庸置疑,她的痛苦是深沉的。她的手掩着眼睛,姿态僵硬,就像一尊在沉思的塑像。她正在哀思,遮着眼睛,闭着眼睛,在黑暗中拨动着使人肝肠寸断的回忆的念珠,她本人就像一个视乎在怀念一个男亡人的女亡人。接着,我突然猜想到她要开始哭了,我是从她背上一阵犹如微风拂柳似的微小颤动猜出来的。 莫泊桑对于人物神情的描绘总是有自己独特的表达的方式,善于从人物的服饰、神情和动作描绘一个人的特色,在这里我看到了一个对于已亡人哀思的寡妇,而不是一个聪明的妓女。","link":"/2017/06/09/莫泊桑短篇小说简评/"},{"title":"清除和去除浮动","text":"本文主要讲述了CSS的清除浮动的原理,并讲述了清除和包含浮动的主要方法。 浮动的原理浮动和定位一样会以某种方式将元素从文档的正常流中删除,而且会影响布局。一个元素浮动时,其他内容会”环绕”该元素。 浮动的特点 浮动元素周围的外边距不会合并(其实是浮动元素形成了新的BFC ,后续讲解) 1234567891011121314151617181920212223242526272829303132<style> .box{ width: 100%; height: 200px; background: #ececdd; margin-left: auto; margin-right: auto; } .inner-nofloat { width: 100%; height: 20px; background: #f7c3c3; margin-bottom: 40px; margin-top: 20px; /*两个nofloat之间的外边距是40px,进行了合并处理*/ } .inner-float { width: 100%; height: 20px; background: #d3cff7; float: left; margin-bottom: 40px; /*float和nofloat之间的外边距是60px,并没有进行合并处理*/ margin-top: 20px; }</style><div class=\"box\"> <div class=\"inner-nofloat\"></div> <div class=\"inner-nofloat\"></div> <div class=\"inner-float\"></div></div> 浮动元素的包含块是其最近的祖先元素 浮动元素会生成一个块级框即使元素本身是行内元素,因此没有必要给浮动元素增加display:block代码 浮动的规则 浮动元素的左(右)外边界不能超出其包含块的左(右)内边界,即左浮动元素的左外边界向左最远只能到达其包含块的左内边界,右浮动元素类似。 1234567891011121314151617181920212223242526272829303132<style> .box{ width: 90%; height: 200px; background: #ececdd; margin-left: auto; margin-right: auto; } .inner-float-left { width: 100%; height: 20px; background: #d3cff7; float: left; margin-bottom: 40px; margin-top: 20px; } .inner-float-right { width: 100%; height: 20px; background: #d3cff7; float: right; margin-bottom: 40px; margin-top: 20px; }</style><div class=\"box\"> <div class=\"inner-float-left\"></div> <div class=\"inner-float-right\"></div></div> 浮动元素的左(右)外边界必须是源文档中(父元素)之前出现的左浮动(右浮动)元素的右(左)外边界,除非后出现的元素浮动元素的顶端在先出现浮动元素的底端下面。这个规则的好处是防止浮动元素的重叠。使用定位时很容易导致元素的相互覆盖。 左浮动元素的右外边界不会在其右边右浮动元素的左外边界的右边。一个右浮动元素的左外边界不会在其左边任何左浮动元素的右外边界的左边。 一个浮动元素的顶端不能比其父元素的内顶端高。 一个浮动元素的顶端不能比其父元素的内顶端高。 源文档的一个浮动元素之前出现的另一个元素,浮动元素的顶端不能比包含该元素所生成框的任何行框的顶端更高。 左(右)浮动元素的左边(右边)有另一个浮动元素,前者的右外边界不能在其包含块的右(左)边界的右边(左边)。 浮动元素尽可能高的放置。 左浮动元素想左浮动尽可能的远,右浮动元素必须向右尽可能远。 浮动带来的布局问题浮动的规则只讲述了浮动元素的左、右和上边界,但是没有涉及到下边界。 1234567891011121314151617181920212223242526272829303132<style> .box{ border: 2px solid #c9f6f2; width: 100%; background: #ececdd; margin-left: auto; margin-right: auto; margin-bottom: 50px; } .inner-nofloat { width: 100%; height: 200px; background: #f7c3c3; margin:20px 0; } .inner-float { width: 100%; height: 200px; background: #d3cff7; float: left; margin:20px 0; }</style><div class=\"box\"> <div class=\"inner-nofloat\"></div></div><div class=\"box\"> <div class=\"inner-float\"></div></div> 如果元素不浮动,那么父块级元素默认会包含子块级元素,从而使子元素显示在父元素之内,但是一旦子元素浮动,那么父元素将不会包含子元素,因为浮动元素不在正常流中,而它的父元素在正常流中,因此处于正常流的父元素并不能包含子浮动元素,从而导致父元素在没有其他子元素且没有设置高度的情况下会产生高度塌陷。CSS2.1澄清了浮动元素行为的一个方面:浮动元素会延伸,从而包含其所有后代浮动元素(其实还是因为浮动元素形成了新的BFC,后续讲解)。所以通过设置第二个box为浮动元素,可以把浮动元素包含在其box内。 那么如果这个父元素的包含块仍然不是浮动元素也可能导致包含块的高度塌陷! 清除浮动的原理利用清除可以设置元素禁止浮动元素出现在它的左侧、右侧甚至是双侧。 1234567891011121314151617181920212223242526272829<style> div { display: inline-block; width: 40%; height: 100px; background: #d3cff7; margin-right: 10px; margin-bottom : 0; padding: 0; } .float { float: left; } .box { height: 50px; } p { border: 1px solid black; margin:0; padding:0; width: 80%; }</style><div class=\"float\"></div><div class=\"box\"></div><p>3333333333333333333333333333333333333333333</p> 123333333333333333333333333333333333333333333 由于div1浮动,p和div1布局重叠,为了解决这个问题,可以使p元素左侧不允许有浮动元素,给p元素添加一个clear:left的样式之后 123333333333333333333333333333333333333333333可以发现p的位置下移从而使p和div1布局不会重叠,其实是使用清除之后,自动增加了p元素的上外边距,确保它落在浮动元素div1的下面。CSS2.1引入了清除区域的概念,清除区域是在元素上外边距之上增加的额外间隔(确保浮动元素不会与该元素重叠),不允许浮动元素进入这个范围,意味着设置clear属性的p元素的外边距并不改变,之所以该元素会向下移动是因为清除区域造成的。div1和div2的高度分别是100px和50px, 因此清除区域的高度在50px左右(不算border和浏览器代理初始样式等)。如果给p元素一个上外边距margin-top:30px,则p元素并不会向下移动30px,而是在解析完样式之后清除区域的高度变成了50px - 30px左右,而p元素仍然位置不变,如果要使p元素下移,则需要使p元素的margin-top值高于最大的清除区域高度50px,并且向下位移的距离也是margin-top值减去最大的清除区域高度。通常情况下,我们当然很难准确计算最大的清除区域高度,因此要使浮动元素div1和p元素有一个确定的值很难通过设置p元素的上外边距获取效果,而是应该设置div1的下外边距margin-bottom(仍然是因为浮动元素形成了BFC上下文)。例如需要确定浮动元素和p元素上下距离为15px123333333333333333333333333333333333333333333 清除浮动的方法浮动容易导致块级父元素的高度塌陷,通过直接设置父元素的高度以及设置父元素为浮动元素并不能很好的解决元素浮动带来的布局问题,因此可以通过clear属性来清除浮动。 追加元素并设置clear属性 优势:简单,布局灵活,浏览器兼容性好 弊端:结构和表现混淆,添加了不必要的DOM元素,不便于后期维护 如果父元素高度塌陷,则可以通过在父元素的尾部追加空的子元素,并利用clear:both解决塌陷问题。 1234567891011121314151617181920212223<style>.box{ border: 2px solid #c9f6f2; width: 100%; background: #ececdd; margin-left: auto; margin-right: auto; margin-bottom: 50px;}.float { width: 25%; height: 100px; float: left; background: #d3cff7; margin:10px;}</style><div class=\"box\"> <div class=\"float\"></div> <div class=\"float\"></div> <div class=\"float\"></div></div> 如果父元素没有设置高度,那么因为三个浮动子元素脱离正常流导致父元素的高度塌陷,如果给第三个浮动子元素加上clear:both的样式,并没有解决高度塌陷的问题,因为非浮动父元素仍然不能包含浮动子元素。 此时如果给父元素的尾部添加一个非浮动子元素并给出样式clear:both,由于这个子元素是非浮动元素,通过清除的原理可以知道相对之前的浮动元素,该非浮动元素会生成一个清除区域,这个清除区域的高度可以促使非浮动元素处于浮动元素的下方,而且非浮动元素和浮动元素之间的准确边距通常由浮动元素的下边距确定,因此导致这个非浮动元素处于三个浮动子元素的下方10px处(三个浮动元素的样式margin:10px导致),又因为父元素包含了这个非浮动子元素,从而使父元素也可以包含浮动元素,解决了高度塌陷的问题(当然添加的非浮动子元素一般都是空元素,例如br)。 12345678910111213141516171819202122232425<style>.box{ ...}.float { ...}.nofloat { width: 100%; height: 20px; background: #f5d5ea; margin:0; padding:0; clear: both;}</style><div class=\"box\"> <div class=\"float\"></div> <div class=\"float\"></div> <div class=\"float\"></div> <div class=\"nofloat\"></div></div> 使用CSS样式插入元素 优势:不破坏文档结构,没有副作用 劣势:使用display:block会使父子元素的垂直外边距重叠(后续详细说明) 原理其实和追加元素并设置clear属性相同,只是使用css样式来处理。 123456789101112131415161718192021222324252627282930<style>.box{ border: 2px solid #c9f6f2; width: 100%; background: #ececdd; margin-left: auto; margin-right: auto; margin-bottom: 50px;}.clearfix:after { content: ''; display: block; clear: both;}.float { width: 25%; height: 100px; float: left; background: #d3cff7; margin:10px;}</style><div class=\"box clearfix\"> <div class=\"float\"></div> <div class=\"float\"></div> <div class=\"float\"></div></div> 包含浮动的原理解决浮动元素带来布局的副作用的方法之一是使用clear清除浮动,但是也可以利用BFC的特性来包含浮动从而解决父元素高度塌陷的问题。 什么是BFCBFC(Block formatting context)直译为”块级格式化上下文”。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。 block-level box是display属性为block, list-item, table的元素,会生成block-level box,并且参与block fomatting context。 具体可以从什么是BFC中了解BFC的特性。 BFC特性 BFC会阻止垂直外边距(margin-top、margin-bottom)折叠(属于同一个BFC的两个相邻Box的margin会发生重叠 ) BFC不会重叠浮动元素 BFC可以包含浮动(计算BFC的高度时,浮动元素的高度也参与计算 ,可以利用BFC的这个特性来“清浮动”,应该说包含浮动。也就是说只要父容器形成BFC就可以) 需要注意的是根元素本身就能触发一个BFC,事实上除了根元素以外以下的方式也能触发BFC float (left,right) overflow 除了visible 以外的值(hidden,auto,scroll) display (table-cell,table-caption,inline-block) position(absolute,fixed) BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此。意思是可以把能创建BFC的盒子当作那个根元素,同时这个创建了BFC的盒子则是一个独立的容器,里面参与BFC的块级盒不会影响到盒子外面的盒子,外面的盒子也不会影响到里面参与了BFC的块级盒。 12345678910111213141516171819202122232425262728293031323334353637383940<style>.box { width: 100%;}.bfc-float-box1 { float: left; width: 100%; background: #ececdd;}.bfc-float-box2 { float: left; width: 100%; background: #f9d7f7;}.bfc-inner-box1 { margin-bottom: 30px; width: 100px; height: 100px; background: #f7c3c3;}.bfc-inner-box2 { margin-top: 50px; width: 100px; height: 100px; background: #d3cff7;}</style><div class=\"box\" style=\"width: 100%;\"> <div class=\"bfc-float-box1\"> <div class=\"bfc-inner-box1\"></div> </div> <div class=\"bfc-float-box2\"> <div class=\"bfc-inner-box2\"></div> </div></div> 两个float的父盒子在为它下面的盒子创建了一个BFC,从而将float盒子里面的子盒子给隔离了起来,因此也就不会margin折叠了。所以上下边距30px和50px并不会重叠,因为不属于同一个BFC,当然在同一个BFC内边距还是会重叠的。同时可以发现每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。 123456789101112131415161718192021222324<style>.box { width: 100%;}.bfc-float-box1 { float: left; width: 100px; height: 100px; background: #ececdd;}.bfc-overflow-box2 { overflow: hidden; width: 100px; height: 100px; background: #d3cff7;}</style><div class=\"box\"> <div class=\"bfc-float-box1\">float</div> <div class=\"bfc-overflow-box2\">overflow</div></div> floatoverflow BFC不会重叠浮动元素,由于第二个div使用overflow: hidden触发了新的BFC,因此它被排布在float元素的右边而不会重叠。需要注意的是形成新BFC上下文中的块级盒的表现形式和根元素下(根元素也也会触发BFC)的块级盒的表现形式是一样的,只是可以理解为它们所处的上下文环境不一样,新的BFC和根元素的BFC各自形成独立空间,接下来要说的就是在处理浮动时为什么表现为display:block和display:table的区别,前者不会形成新的BFC,而后者则会。 清楚浮动和包含浮动的区别display: block在没有形成新的BFC时,如果块级父元素height为auto或不设置,没有设置padding或border属性,且只有块级子元素,那么父元素的默认高度将由子元素的盒模型决定,从最高块级子元素的外边框边界到最低块级子元素的外边框边界之间的距离(注意不包含子元素的的外边距margin值) 1234567891011121314151617181920<style type=\"text/css\"> .father { width: 100%; background: #ececdd; } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 30px; background: #d3cff7; }</style><div class=\"father\"> <div class=\"son\"> son </div></div> son 如果fahter块有内容或者有padding或border属性 123456789101112131415161718<style type="text/css"> .father { width: 100%; background: #ececdd; border: 1px solid #f9d7f7; } .son { ... }</style><div class="father"> <div class="son"> son </div></div> son 可以看出上面两个例子的不同之处在于第一个例子father块的大小和son块一样,那么如果两个一样的此father块之间的外边距如何计算呢? father块带border属性 1234567891011121314151617181920212223242526<style type=\"text/css\"> .father { width: 100%; background: #ececdd; border: 1px solid #f9d7f7; } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 50px; background: #d3cff7; }</style><div class=\"father\"> <div class=\"son\"> son </div></div><div class=\"father\"> <div class=\"son\"> son </div></div> son son father块不带border属性 sonson 可以发现两个son块在外边距上发生了重叠,使得外边距为较大值50px;如果此时给第二个father块一个margin-top: 40px;的属性值,外边距重叠仍然使两个son块的距离为50px,因此father块一个margin-top属性值就不能起到效果了。 sonson display: table如果使father块触发BFC上下文呢? 1234567891011121314151617181920212223242526<style type=\"text/css\"> .father { width: 100%; background: #ececdd; display: table; /*触发新的BFC上下文*/ } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 50px; background: #d3cff7; }</style><div class=\"father\"> <div class=\"son\"> son </div></div><div class=\"father\"> <div class=\"son\"> son </div></div> sonson 可以发现两个son块之间的距离为70px,并且父元素的高度还包含了son块的margin值,如果此时同样给第二个父元素一个margin-top值,可以发现此时的40px有了效果 sonson 当然如果把son块换成float元素(需要注意的是son块又形成了新的BFC),那么效果仍然一样,而且不会产生高度塌陷,因为BFC会计算浮动元素的高度,而不会使father块高度塌陷,也就起到了包含浮动的作用 123456789101112131415161718192021222324252627<style type=\"text/css\"> .father { width: 100%; background: #ececdd; display: table; /*触发新的BFC上下文*/ } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 50px; background: #d3cff7; float: left; }</style><div class=\"father\"> <div class=\"son\"> son </div></div><div class=\"father\"> <div class=\"son\"> son </div></div> float sonfloat son 所以最后你可以比较一下以下两种的情况的区别了 去除浮动 12345678910111213141516171819202122232425262728293031<style type=\"text/css\"> .father { width: 100%; background: #ececdd; display: block; } .father: after { content: \"\"; clear: both; } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 30px; background: #d3cff7; }</style><div class=\"father\"> <div class=\"son\"> son </div></div><div class=\"father\" style=\"margin-top: 40px;\"> <div class=\"son\"> son </div></div> 包含浮动 12345678910111213141516171819202122232425262728293031<style type=\"text/css\"> .father { width: 100%; background: #ececdd; display: table; } .father: after { content: \"\"; clear: both; } .son { height: 100px; width: 100%; margin-top: 50px; margin-bottom: 30px; background: #d3cff7; }</style><div class=\"father\"> <div class=\"son\"> son </div></div><div class=\"father\" style=\"margin-top: 40px;\"> <div class=\"son\"> son </div></div> 那么你就会清楚为什么bootstrap清除浮动的less是这样的 1234567891011121314// The use of `table` rather than `block` is only necessary if using// `:before` to contain the top-margins of child elements..clearfix() { &:before, &:after { content: \" \"; display: table; } &:after { clear: both; }} 参考文献 CSS权威指南 什么是BFC","link":"/2017/08/02/清除和去除浮动/"},{"title":"那一年,我毕业了","text":"那一年,有一场说走就走的旅行。那一年,我毕业了。 兰州篇2017年6月20日,出发远行。从杭州坐上了去西北的火车。当我第一次睡上火车卧铺时,对于这个狭窄的空间和即将开始的旅行产生了一种时而闷悸时而兴奋的矛盾心情,幸好之后的时光里一直被新奇的风景吸引了目光。 在去兰州的途中,人生第一次遇见了黄土高原,那是一个荒寂的国度。同时在火车上认识了一个在杭州读大学的学妹李亭蔚,这也是我旅途中认识的第一个伙伴,是她告诉了我这片荒寂之地的贫穷和孤独,而黄土坡上所能看到的绿油油一片片的便是玉米和青稞地。 在火车上的第一夜睡的并不好,时而伴随着火车变轨的撞击声,这种声音促使我醒来又入睡,于是迷迷糊糊的就到了兰州。兰州给人的感觉就是一个狭长而古旧的城市,下了火车站,和旅途的第一个伙伴告别之后,我便奔赴了人生的第一个青年旅社,青旅的老板并不是一个特别会打扫的人,所以住的地方稍微有一些凌乱。 缘分的是,遇到了一个特别能说会道的孩子,这个孩子叫刁仕豪,一个广旷而带有豪性的名字。他不停的和青旅老板讲述着环青海湖所拍摄的种种美景,事实上你完全看不出来他和青旅老板也才刚刚相识。当然我被他的话语和美景所吸引了。我们的缘分也就从此开始,想着第二日便要奔赴西宁,我邀请他和另外一个小伙伴一起去看母亲河,中山桥上的母亲河。 中山桥的母亲河果然就是黄黄的河水,以至于分不清到底是水更多还是黄沙更多。我和刁仕豪便在这座在母亲之上的桥上合影,互相露出了不算洁白的牙齿咧嘴的笑。 那天晚上,刁仕豪同学和我讲述了很多关于旅行的故事,吃的、玩的和美女。我们谈笑风生,尽不显尴尬。那天晚上,我吃到了兰州的特色街边小吃醪糟,里面有花生和葡萄干,带着一股牛奶和酒的混杂味,甜九分,酸半分,好吃,如果硬要和南方人形容,那就是烧仙草中没有仙草的味道相似。 那一天我们怀着兴奋的心情聊到了半夜。那一天的第二天,我们怀着憧憬的心情特地赶去吃兰州最有名的马子禄牛肉面,其实我不喜欢吃面,特不喜欢的是放着葱花的面,但是为了享受原汁原味我还是默认了这种带着葱花的吃法,不得不说,牛肉是感人的牛肉。 吃完了牛肉面,本该是分道扬镳的时候了,虽然舍不得刁仕豪同学,但是毕竟殊途不同归,我要去的地方正好是他去过的地方。一个要前往西宁,另一个本该去的地方是西安,安宁两个字听起来让人舒心,却是截然不同的两个方向。缘分本该就此掐断,然而刁仕豪同学不知道哪根筋抽了,居然跳下了去西安的火车,和我一同又去了他熟悉的西宁,确实,缘分这种东西本来也可以令人感动的藕断丝连,于是怀着惊讶、莫名、感激和兴奋的心情,我们一同前往西宁,当然这里省略了一些同样有缘分而不在叙述的人。至此,短暂兰州的一天和漫长的火车旅途结束。 西宁篇兰州到西宁也就3个小时的火车行程,到达之后便会发现相比兰州的古旧,西宁更让人觉得新鲜。 当然,可能也因为青旅的环境比兰州的好更多,而在刁仕豪同学的说法看来,青旅的老板如果是老板娘,那么必定会是一个干净的青旅,不仅如此,青旅一定要靠近火车站,于是乎,他成功的把我这个客户推销给了他心仪的西宁青旅老板娘。 说到心仪大概一张照片便可以看出亲密的两人,我甚至怀疑这货能再次回到西宁,必定是极其想念这位青旅老板娘。当然,说到青旅老板娘,非常惭愧的是,我甚至都忘记了问她的名字,只知道她是一位细腻中带着粗犷的女生,看起来似乎有些大大咧咧,实际上却必定是一位内心温柔至极的女生。 说到这位骚里骚气的刁同学,和青旅老板娘确实看起来性格都不错。所谓不错,那不就是般配么? 也可以看出青旅老板娘确实美丽动人。 在西宁住了一晚,第二天便和刁同学奔赴门源去看花海,门源的天是那么的蓝,但是却没有到花开的季节 事实上一星期后的门源是这样的黄 不过,依然看到了青稞、草原、雪山和宽阔笔直的马路,祁连山脉上的雪上和俯视着的草原是那么的壮阔。满眼望去绿油油的田野,一眼望不到尽头的马路,远处屹立着的雄壮的雪山以及青青大草原,都是那么的令人舒畅。 最后,我和刁仕豪同学来到了岗什卡雪山,这座起点海拔便有3700米的雪山,着实花费了我们4个小时进行攀登。 在这座低氧度的雪山上,我第一次体验到了什么是缺氧的感觉,而刁仕豪这个家伙却完全没有什么感觉,着实让人羡慕。最后这座每走10米便要休息一会儿的雪山,还是被我们的努力所感动,安安静静的躺在我们的身旁像是对我们表示了一种沉默的屈服。 当然,最后的我们是胜利的,欢呼的,雀跃的!西宁的第一站门源也就这样安安静静的落下了帷幕。 西宁的第二站当然是青海湖,遗憾的是刁仕豪同学没有和我一同前往,庆幸的是遇到了临安的老乡,这种缘分真的是可妙不可言。看起来,这个老乡穿着藏服给人的感觉就是一个憨厚可爱的藏人。同行的共有四个人和一个司机,我们先是花了很长的时间到了这个叫做倒淌河的景点,在这里,你可以穿藏服、骑耗牛和骑马,让你体验一把不是特别过瘾的藏族人作习,当然也没什么特别可以说的。 接着便到了我们最想去的地方青海湖,可惜天公不作美,没有看到蓝天倒影下的青海湖。 幸好在开车司机的鼓励下,我们体验了一把水陆两系车,确实不错。你还能认出那个穿着藏服的憨厚小子么?啊哈哈! 因为天气的原因,确实没有拍到纯净透彻的青海湖。所以我们最终带着遗憾的心情前往了金沙湾,同时我们也感受到为什么那么多人愿意绕着青海湖骑行,确实那些马路宽阔而笔直,要是心情不够美丽,还能停下眺望一下碧蓝的青海湖。 金沙湾就是青海湖旁边连绵的小沙包,远处黄黄的小土包就是。 不过,沙子确实细而多,密密麻麻的看起来还挺纯净,所谓的纯净就是除了沙子你再也找不到其他东西。 而若是你躺在上面甚至还能纵享丝滑。 西宁的旅行至此也快要结束,唯独迟迟没有说到西宁的美食,兰州有醪糟,而西宁有老酸奶。遇到了西宁的老酸奶,你会发现一鸣的酸奶真是白叫了酸奶这个名字。只要3块钱,你就可以尝到西宁美味的酸奶。需要知道的是,美味的东西必定是古色古香的,西宁的老酸奶虽然是放了添加剂,不过你仍然能够品尝出那种发酵之后的酸味,入口之后先化开的就是这股不是特别酸的酸味,之后才是特有的奶味,最后是淡淡的甜味,当然如果添加剂放多了,那便会覆盖原始的奶味,我想酸奶的老板应该深谙此道,因此酸奶酸奶,原来酸字是这样的由来。 最好的当然是不放添加剂的酸奶,有幸我便尝到了原始的牦牛酸奶,这是藏民自家的牛奶做的,刚拿到手的时候你会发现上面撒了满满一层的白糖,这可不是抹着添加剂糖精,白糖才是最好的东西。所以你吃一口带着白糖的酸奶时,你会发现刚到嘴里的酸味不是特别的酸,但是奶味却足够到位,有了白糖的作用,入口的感觉真的是特别棒的淡酸的奶味,但是当把面上的糖吃完之后,再次尝试的酸奶却是真的酸到发苦,尽管奶味实实在在,但是实在又是太酸了,所以很难让人接受这种原始的味道,但是呢,这不才是真正的牦牛酸奶么。 西宁酸奶对于我这样喜欢甜食的人来说,确实是最美味的美食了,所以在离开西宁之前的最后,我还是过足了酸奶的瘾才舍得离开。 拉萨篇告别西宁,最终的目的地当然是拉萨这个神秘而神圣的佛教圣地。从西宁到拉萨的青藏铁路,不仅会侧绕青海湖,还需要经过荒芜的可可西里大草原和唐古拉山脉。由于青藏铁路海波总体高于4000米,因此火车是提供氧气的火车。在忍受着缺氧的环境下,你唯一可以享受的便是车外的风景,雄壮的唐古拉雪山、高海波雪地、荒芜的大草原、奔驰的野马、可爱呆滞的藏羚羊(可惜的没有抓拍)、低厚的云层。 到了拉萨,首先认识的当然是青旅客栈的老板李岩,这是一个看起来瘦瘦的男孩,喜欢扎着一个小辫子,稍有些文艺气息,眼睛和我一样小小的,给人的感觉极好。 拉萨其实并不大,出了市内的布达拉宫(达拉喇嘛的冬宫)、罗布林卡(达拉喇嘛的夏宫)、大昭寺、色拉寺、哲蚌寺、八廓街以及一个非常有特色的时光旅行书店便没有什么特别好玩的地方了,而市外其实玩的就比较多了,比如有小江南之称的林芝、日客则附近的珠穆朗玛峰、纳木错、羊湖(羊卓雍错)以及遥远的阿里地区。 休息了一晚,并没有什么异常的高原反应,第二天我便和一个叫段立乐的女生一同前往羊湖。羊卓雍错(羊湖)与纳木错、玛旁雍错并称为西藏的三大圣湖。羊湖的美,是碧蓝的美,除此之外,羊湖更像是一个安安静静的小女孩躺在那里供你欣赏。 羊湖回来的时候就在白塔下,因此就欣赏了雄壮的布达拉宫 第二天随着李岩去了拉萨的天堂时光旅行书店,书店总是能够让人旅行时疲惫的心灵得到小憩。听着书店的工作人员讲述各世达拉喇嘛和班禅的事迹,讲述着各种藏教文化,我很有兴趣的买下了《仓央嘉措》和《西藏宗教》,想着日后尽管到过拉萨,在别人面前却说不出这个佛教圣地的种种,日后总得带着好奇去了解一些西藏的宗教文化。当然,也买了一些据说是带有书店老板亲自拍摄的西藏景观的明信片,想着邮局也更有意义。 上午逛完书店,下午便去了琳琅满目的八廓街,八廓街中都是一些围绕大昭寺而建的商业店铺,有卖天珠的、有卖佛经的、有卖西藏特产的……在一家养有一只白猫的店铺里我品尝了西藏的甜茶和酸奶,给人的感觉不错,甜茶好喝。在大昭寺门口,除了虔诚的朝圣信徒还是虔诚的朝圣信徒,这种氛围给我的感觉很是肃然,我想这是对于信仰的敬畏。 看着这些朝圣者,对于我来说是非常令人震惊的事,甚至你都能看到一个看起来有些老气的妇女带着两个幼小的女孩在街上边走边朝圣,其中的一个小女孩一起一朝拜,可能她还小什么都不懂,但是她知道这对于她的人生来说是一件非常重要的事,所以她做的非常的认真。这一幕让我很是感动,感动的掉眼泪。 [这是一段视频,如果看不到视频说明您的浏览器不支持播放。] 大昭寺前的信仰使我对自己的人生产生了新的思考,人生一世,草木一秋,确实不能在这短暂的时光中浪费时光,而是要做些自己认为有意义的事,比如当前的旅行。出了八廓街,我的心情稍微不那么沉重了一些,于是我又去看了夜里的布达拉宫,依然是那么的壮阔。 拉萨的第三天和一个叫朱江丽的小女孩去了纳木错,依然是西藏的三大圣湖之一。和羊湖相比,纳木错给人的感觉更加的旷阔,我个人也更喜欢纳木错这种旷阔的碧蓝美。 当然每次回来都必定会在布达拉宫旁的白塔下车,以至于我又可以看一次并拍一次布达拉宫。 第四天又在市内逛,不过这次认识了来自北京的暖暖、来自广州的高妹和来自上海的唐吉吉,我们怀着虔诚和敬畏的心情,一起参拜了大昭寺,参拜了释迦摩尼十二岁等身像,为家人祈福,为朋友祈福。 出了大昭寺,我再次陪同她们逛了八廓街。 我们在一家叫土黄色小楼玛吉阿米(据说仓央嘉措与情人玛吉阿米幽会的地方是一个土黄色的小楼)的店遇到了小学弟。玛吉阿米店里有一只高冷的看着窗外的小黄猫,什么喧闹的事情都很难引得它回头看上一眼。 那一晚,我认识了一个可爱的藏族小伙旦增洛桑,虽然只有18岁却看起来像个男子汉,从他那里得知一般藏族小伙都不识字也不上学。 在拉萨的第五天,五人小分队开始了为期三天的林芝之旅。林芝位于拉萨的东面,又被称为西藏小江南,风景秀丽,平均海拔约为3100米,又多生产藏药,例如松茸、林芝等。当然林芝的四月天里桃花漫山遍野,才是最好看的季节。旅行的第一站到了巴松措。 第二站是卡定沟。 林芝的第一天大部分时间其实都在路上,晚上我们五人在林芝市的旅舍里打扑克(五个人的扑克,有点类似狼人杀),不得不说,小学弟的头脑还是非常机智的,而高妹深藏不露,只有我、暖暖和唐吉吉这种后知型扑克选手才会在事后恍然大悟。不得不说,扑克游戏使我们对彼此有了更深刻了解,高妹的低调和善解人意、学弟的机智和与人为善、暖暖的挑剔、唐吉吉的活泼,然后我,我是班长!第二天我们去了雅鲁藏布江大峡谷,不得不说,林芝的三天一直都在云雾缭绕和雨天里,所以也就没有看到南迦巴瓦峰。 林芝的第三天是回拉萨。 拉萨的最后一天,我们一起去了小昭寺和罗布林卡。 至此,拉萨旅行结束,五人小分队中高妹回了广州,小学弟去了上海,暖暖和唐吉吉则仍然留下继续,而我则一人去了成都。缘分真的是可遇不可求,把本无任何联系的五个人紧紧的拴在了拉萨,或许,在不久的将来我们还会以其他形式在相会。 成都篇西藏真是风景独好,可是最终仍然需要跟它告别,坐上了去往成都的火车,仍然走青藏铁路,途经西宁转火车,然后前往成都,沿途当然又是一路风景,你可以晚上的9点以后看见藏人赶着牧群回家,因为即使是9点40分,美丽的大草原还有夕阳可寻。 到了成都就去了我姐家里,第一件事当然是吃成都的美食。然而可能是地方差异水土不服,吃了一次串串就再也没有口福了,不仅拉肚子,口肠溃疡到不能说话,甚至后面回了杭州一时仍然好不了。 第二件事当然去锦里转了转,类似于杭州的河坊街,不过个人感觉比河坊街更有浓厚的街巷气息,除了桃源结义,你还能看到成都街头酒吧的驻唱,还可以吃到各种成都小吃,以及变脸谱的戏法,当然神奇的沙画也是一件美妙的食物。 第二天当然是老姐带着我去春熙路看美女,都说成都出美女,人灵地杰,正好我们去的时候又是周末,所以确确实实也看到了成都独特一方的美女,身材矫健,性格火辣,和杭州秀气的美女各成一番风味。要说觉得最有意思的,那就是去看蜀绣,精致美妙,颜色素雅而不失单调。 最后,感谢老姐在成都对于的照顾和关怀。 总结篇第一次一个人开始一场说走就走的旅行,哪怕看起来有些茫然,但是在路上自然就遇到了有缘的人,他们也和你一样,在乎于在乎于心中有一片不属于家乡的土地,这些人这些故事这些照片,把你的记忆定格在永远美好的时间戳里。旅行的缘分,希望藕断而丝连。旅行,是一场有意义的心灵洗礼。旅行,也是告别另一个时间戳。","link":"/2017/07/16/那一年,我毕业了/"},{"title":"他","text":"数十载虽匆匆而过,尤想起他,心中甚是怀念,特作此文悼念之。 记得童年时尤喜欢猫,似乎由于祖母养的黑猫。那时候我眼里的他,是神奇的,是可爱的,但也是古怪的,甚至偶尔是孤独的。他和大多数猫一样不喜欢待在家里,喜欢独自到处游荡,但是他与大多数猫不一样的是,他不挑食,不喜欢贪小便宜,会准时回来觅食,所以他是我记忆里最模糊却又时间最长的一只猫。他可爱的很,有一次我亲眼看见他在捉弄一只老鼠,就像是他专有的玩具一样,用锋利的爪子一咕噜一咕噜的挑逗它,可怜的老鼠被他玩的团团转,怎么都逃不出他的手掌心,最后实在是没有了兴致就一咕噜的挠死它。终究是养不住,后来他还是离家出走了,不知道是因为什么,很是令人莫名其妙。后来祖母又相继养了几只小灰猫,但是都夭折了,之后的一段时间里,家里就断了猫的踪影,似乎谁也不愿意再去经历这种很没有必要的伤痛。直到小学四年级的某一次,父亲带着我去姨婆家玩,正好她家的猫妈妈生了几只小猫,于是我便嚷着喊着要抱一只回家,父亲终究拗不过我,便领了一只回来,还是一只小灰猫。对于小灰猫,家里人还是有点阴郁的心情,毕竟已经夭折过了好几只,于是这一次所有人都很是上心,很是照顾他。印象最深刻的莫过于他小时候爬楼梯的样子,那时候他站起来还只有阶梯的一半高,但是总喜欢不停的爬楼梯,步履蹒跚的样子,然后一个不小心便扑通扑通的从楼梯上滚了下来,每每如此,总能逗得我们开怀大笑。大约一年之后,他便会独自深夜出去觅伴,总是学着别人的样子,开始低沉的嗷叫,想要吸引异性的注意,结果总是引来一阵阵厮打,每每这时候叫的最可怜的也是他。母亲最见不得他懦弱的样子,无奈好几次都起床出门去唤他回来。然后第二天就对着他说教一番,他似乎也能听懂,低着头侧着耳,正襟危坐,然后露出一副很委屈的样子。那时候我寄宿在学校,只能在星期五放学后才能回来,一到家,我就满地找他的身影,他看见我也会远远的就”喵喵喵”的呼唤我,然后轻悄悄的竖着尾巴贴了过来,扭着个小屁股很是优雅。慢节奏的我们,总能在后院度过很长的时间也不会觉得无聊,他不粘人,但他喜欢粘着我,喜欢我捞他的爪子,喜欢我弹他的耳朵,喜欢我摸他的头,然后眯着眼睛很是享受的样子,时而轻轻的就”喵”的回应我一声。但是他总改不了他的坏毛病,一到半夜就会外出觅伴, 然后总是引来一阵阵的厮打,可是他又不擅长打架,起初母亲呼唤他还是很听话的,可是随着时间长了,他大多数时候都执拗的不愿意回来。到了冬天,天气冷了,他就会乖巧一些,一到晚上就会蜷缩在我的床尾,有的时候我都还没睡着, 他却开始咕噜咕噜的打起呼来,让我很是厌烦,我偶尔也会一脚就把他踹下去,但是不一会儿,他又凭着轻巧的身影,不知不觉的又在床尾的某个地方打起呼来。 和祖母的黑猫一样的是他不挑食,也不喜欢贪小便宜,他的认知很有规律,不会因为一些意外的原因就逾越这些规律。所以他是最乖巧的,也不会让我们觉得他很孤独,或者他很难理解,多数的时候,他也愿意坐在我们身边,然后一副想要和我们一起探讨话题的样子,尽管他不知道我们在讲什么,但是他偶尔在舔了舔自己的爪子之后,也会抬起头轻轻的对我们说”喵”~偶尔他也可爱的很,记得我那时特别喜欢钓鱼,他就会很好奇的伸长了脖子来看我钓回来的鱼儿,然后就会侧着个头屏息凝视它们,慢慢的伸出爪子想去挠它们,可是等到溅起了水花他又立马跳了出去,然后又转过头来……时间是那样的匆匆而过,陪伴了我三年的他,最终还是走了。爸爸说他是自己走了,就像黑猫一样,没有原因,很是令人莫名奇妙。每次我一回来总会去后院寻找他的身影,仿佛他就在那里,摊着双脚,趴在那里日光浴,然后对着我说,”难道还有比这日光浴更惬意的么,快来快来”。他走了之后,只要看见和他一样肤色的同伙,我总是忍不住想上去呼唤,似乎那就是他,然后他便轻悄悄的迈着优雅的步伐,竖着尾巴扭着屁股走了过来,抬起头,眯着眼,贴着我的裤子蹭一蹭他的脸,”喵”的回应我一声。 他走了,我便决定这辈子不再养猫。","link":"/2017/09/24/他/"},{"title":"挪威的森林里","text":"迷茫、独孤、珍惜,但不是死亡。 村上春树臆想中的那口井在草地和杂木林的交界处,位置很偏僻,深的发黑,一般人很难发现,甚至有没有都是一回事。然而他说一旦有人掉进这口井,那么必然是很难再爬上来,如果直接摔死了那倒还好,要是摔个半死不活那才是真正的半死不活,这就是《挪威的森林》。可能对于正常人而言不会迷失在草地和杂木林的交界处,甚至永远到不了这口井的附近。但是村上春树塑造的直子好像就是掉进了这么一口深的发黑的井,因为她从小青梅竹马的爱人木月在十七岁那年莫名自杀(其实我并不是特别能理解失去了青梅竹马之后,为什么时间就是治愈不了她的心灵,可能我就是没有失去过这样一个人,当然我也没有这样的青梅竹马),而主人公渡边彻也是在恍恍惚惚中体会到了好友之死的莫名以及死的近切,以至于觉得生和死并不是分离的(生和死并不是对立面?我是那种一想到死后的情景,死之后是什么?死之后是永恒的无?那么是不是永远没有了我?那是不是….就会特别的恐慌的人)。渡边彻带着死作为的生的一部分活了下来,但是他给我的感觉是一个不够坚强还特别容易放弃的人,尽管他并没有放弃直子,他也并没有努力去发现那一口井,事实上可能连他自己都迷失了。渡边彻给我最好的印象是他会毫不犹豫的说真话,哪怕这话别人并不爱听。渡边彻是一个孤独的人,这一点很容易看出来,因为他不愿意让别人去了解他,也不愿意去了解别人。尽管他爱着直子,但是他其实并不了解直子,当然直子也不并爱他。《挪威的森林》里没有几个正常的人,也没有几个不正常的人,当然这些是他臆想出来的,并且也是在现实中不合理在书中又特别合理的一部分,他的书中绿子就是一片绿洲,努力,挣扎,拼命想要得到爱,这些正好都是主角渡边彻所没有的也不会有的东西。如果书中硬是要我选一个喜欢的女性,我会选择玲子,我不喜欢直子的委婉含蓄,亦不喜欢绿子的坦率天真,而是喜欢玲子的体贴入微。还有就是我很庆幸没有在大学之前读《挪威的森林》,因为它确实是一本让人觉得消极的书籍,书中的人可以死的那么干脆,又那么不干脆,而且让人觉得孤单,是的,孤单是因为我们像主角一样觉得别人理解与不理解自己真的无所谓,甚至不愿意让人去理解,也不愿意理解别人。当然也越来越不懂得珍惜(尽管我痛恨渡边彻不懂得珍惜绿子, 哪怕他不爱她)。是啊,珍惜这种东西,可能永远只有失去了才能体会的出来吧?孤独这种东西,可能永远只有真正孤独的时候才能体会的出来吧?所以啊,总是有这么迷茫那么迷茫的时候,就像《挪威的森林》一样,徘徊着徘徊着,但是我想总不至于掉进了井里,最后不知道下一次是什么时候再拿起这本书。","link":"/2018/01/25/挪威的森林里/"},{"title":"http协议分析","text":"Web是建立在HTTP(HyperText Transfer Protocol,超文本传输协议)上通信的。本文是一篇HTTP协议学习笔记,补充一下HTTP协议的基础,这对于理解Ajax以及前后端交互过程绝对是非常有帮助的,本文章主要讲述Web基础和简单的HTTP协议…… Web基础使用HTTP协议访问WebWeb页面是如何呈现的? 客户端通过指定的URL地址获取服务器端资源 服务器端使用HTTP协议传输文件资源 HTTP诞生Web历史 1989.03 HTTP诞生 1990.11 CERN(欧洲核子研究组织)研发世界上第一台Web服务器和Web浏览器 1993.01 现代浏览器的祖先NCSA研发的Mosaic问世 1994.12 网景通信公司发布了Netscape Navigator 1.0 1995.xx 微软公司发布了IE 1.0和2.0 1995.xx Apache 0.2发布 1995.xx HTML2.0发布 2004.xx Mozilla基金会发布了Firefox浏览器 HTTP历史 HTTP/0.9 HTTP/1.0之前的版本 HTTP/1.0 该协议标准仍被广泛使用至服务器 HTTP/1.1 目前主流的协议版本 网络基础TCP/IPHTTP是TCP/IP协议族中的一个子集。 TCP/IP协议族TCP/IP是互联网相关的各类协议族的总称,包括 HTTP — HyperText Transfer Protocol,超文本传输协议 FTP — File Transfer Protocil,文件传输协议 DNS — Domain Name System,域名系统 TCP — Transmission Control Protocol,传输控制协议 UDP — User Data Protocol,用户数据报协议 IP — Internet Protocol,网际协议 PPPoE ICMP FDDI IEEE 802.3 TCP/IP分层管理分层的好处是各层之间互不干涉影响,如果协议中的某个地方需要修改,只需要修改某一层即可,而不需要改变整体。只要把各层之间的接口部分规划好,每个层次内部的设计就能够自由改动了。分层如下: 应用层 传输层 网络层(网络互连层) 链路层(网络接口层、数据链路层) 应用层决定了向用户提供服务时通信的活动。包括FTP协议、DNS协议和HTTP协议等。 传输层上层是应用层,下层是网络层,提供处于网络连接中的两台计算机之间的数据传输。包括TCP协议和UDP协议。 网络层(网络互连层)下层是链路层,用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。该层规定了传输路线(有路径算法),并把数据包送给对方。网络层的作用其实就是在众多的网络设备之间传输时选择一条传输路线。 链路层(网络接口层、数据链路层)用来处理连接网络的硬件部分,包括控制操作系统、硬件的设备驱动、网络适配器(网卡)、光钎、还包括连接器等传输媒介。总而言之,硬件上的范畴都在链路层范围之内。 TCP/IP通信传输流传输流 发送端封装 提示:发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。 接收端解封接收端的解封流程正好是发送端的逆流程。 提示:接收端在层与层之间传输数据时,每经过一层时必定会把对应的首部消去。 DNS、TCP、IP负责域名解析的DNS服务DNS服务位于应用层。提供域名到IP地址之间的解析服务。计算机不仅可以赋予IP地址,也可以被赋予主机名和域名,例如域名www.baidu.com。IP地址不好记,谁能记住一大串数字,域名就比较好记,所以访问对方计算机时,可以通过域名访问而不是IP地址访问。DNS可以通过域名查找IP地址。 确保可靠的TCP协议TCP协议位于传输层,提供可靠的字节流服务。字节流服务是将大块的数据分割以报文段为单位的数据包进行管理,可靠的传输服务是指准确可靠的把数据传输给对方。为了实现可靠传输,TCP协议采用三次握手传输策略。 负责传输的IP协议IP协议位于网络层,作用是把各种数据包传送给对方。要传送给对方,需要两个条件,IP地址和MAC地址。 类型 说明 区别IP 指明了节点被分配到的地址 地址可变MAC 网络适配器(网卡)所属的固定地址 地址不可变 使用ARP协议凭借MAC地址进行通信,ARP是一种用以解析地址的协议,根据通信方的IP地址就可以反查出对应的MAC地址。 各种协议与HTTP协议的关系第一步 第二步 URI和URL省略。 简单的HTTP协议本章节讲解HTTP/1.1版本的协议结构。 HTTP通信HTTP协议和TCP/IP协议族中的其他协议都是用于客户端和服务器之间的通信。 客户端:请求访问文本或图像等资源的一端 服务器端:提供资源响应的一端 在两台计算机之间使用HTTP协议通信时,在一条通信线路上必定有一端是客户端,另一端是服务器端。 HTTP请求和响应 HTTP协议规定,请求从客户端发出,最后服务器端相应该请求并返回。注意必须先从客户端开始建立通信,服务器端在没有接收到请求之间不会发送响应。 请求报文客户端发送一个请求,请求报文构成示例如下: 12345678910//请求方法,URLRequest URL:http://localhost:7101/signupRequest Method:POST//请求首部字段Connection:keep-aliveContent-Type:application/x-www-form-urlencodedContent-Length:29Host:localhost:7101//内容实体(请求主体)name=admin3&password=22222222 请求报文一般由以下构成 请求方法,URI(粗略的可以说是URL) 可选的请求头首部字段 内容实体(请求主体) 响应报文12345678//响应状态码Status Code:200 OK//响应首部字段Date:Mon, 20 Jun 2016 10:38:42 GMTContent-Length:9Content-Type:application/json; charset=utf-8//响应主体{\"msg\":2} 响应报文一般由以下构成 响应状态码 用于解释状态码的原因语句(例如OK,Not Modified等) 可选的响应首部字段 响应主体 Ajax示例12345678910111213141516171819202122232425262728293031function postFormData(url,data,callback){ if(window.XMLHttpRequest){ //创建一个XHR对象 req = new XMLHttpRequest(); } else if(window.ActiveXObject){ //兼容IE req = new ActiveXObject('Microsoft.XMLHTTP'); } /*1.请求方法和URL*/ request.open('POST',url); request.onreadystatechange = function(){ if(request.readyState === 4){ /*4.响应状态码*/ if(request.state === 200){ /*5.可选的响应首部字段*/ var type = req.getResponseHeader(\"Content-Type\"); var size = req.getResponseHeader(\"Content-Length\"); /*6.响应主体*/ if(type.indexOf('xml') !== -1 && request.responseXML){ callback(request.responseXML); //XML Document对象响应 } else if(type === 'application/json'){ callback(JSON.parse(request.responseText)); //JSON响应 } else{ callback(request.responseText); //字符串响应 } } } }; /*2.可选的请求头首部字段*/ request.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); //设置Content-Type /*3.请求主体*/ request.send(encodeFormData(data)); //发送表单编码数据} HTTP是不保存状态HTTP是一种无状态协议,HTTP协议自身不对请求和响应之间的通信状态进行保存。每当新的请求发送时,就会对应新的响应产生,协议本身并不会保留之前一切的请求和响应报文信息。当然,无状态导致了业务处理能力减弱,比如登录网站时,跳转到该站的其他页面,也需要能够继续保持登录状态,此时就需要保存用户的状态,所以为了实现这个状态功能,引入了cookie技术。有了cookie再用HTTP协议通信,就可以管理状态了。 请求URI定位资源HTTP协议使用URI定位互联网上的资源,当客户端请求访问资源而发送请求时,URI需要将作为请求报文中的请求URI包含在内。 HTTP请求方法 请求类型 说明 作用 支持的HTTP协议的版本 GET 请求访问已被URI识别的资源,指定的资源经服务器解析后返回响应内容 获取资源 1.0、1.1 POST 尽管GET也可以传输实体主体,但是一般还是用POST传输,POST的主要目的并不是获取响应内容 传输实体主体 1.0、1.1 PUT 就像FTP协议的文件上传一样,要求在请求报文的主体中包含文件内容,没有验证机制,一般Web网站不使用 传输文件 1.0、1.1 HEAD HEAD方法和GET方法类似,区别是不获取报文响应主体,用于确认URI的有效性及资源更新的日期等 获取报文首部 获取报文首部 1.0、1.1 DELETE 与PUT方法相反,也没有验证机制 删除文件 1.0、1.1 OPTIONS 查询针对特定请求URI指定的资源的支持的方法 询问支持的方法 1.1 TRACE 通常不会用,容易引发XST(跨站追踪)攻击 跟踪路径 1.1 CONNECT 实现用隧道协议进行TCP通信 要求用隧道协议连接代理 1.1 提示:HTTP/1.0还支持LINK(建立和资源之间的联系)、UNLINK(断开连接关系)方法,但是在HTTP/1.1中被废弃。此外,方法名区分大小写,注意要用大写字母。 持久连接节省通信量HTTP初始版本中,每建立一次连接,HTTP通信就要断开一次TCP连接。随着HTTP请求的主体内容越来越大,显然这样的性能是不够的,比如获取一个网页信息时,获取HTML文档建立和断开一次TCP连接,获取图片又是一次,获取另外一张图片又是一次,增加了通信量的开销。 持久连接针对上述问题,HTTP/1.1和部分HTTP/1.0想出了持久连接(HTTP keep-alive)的方法。只要任意一端没有明确提出断开连接,则保持TCP连接状态。持久连接旨在建立1次TCP连接后进行多次请求和响应的交互。在HTTP/1.1中所有的连接默认都是持久连接,但在HTTP/1.0内并没有标准化。 管线化持久连接造就了管线化方式发送。以前发送请求是串行的,发送一个请求必须得到响应才能发送下一个请求,管线化技术出现后,不用等待响应亦可直接发送下一个请求。这样可以做到同时并行发送多个请求。 使用Cookie的状态管理HTTP是无状态协议,于是引入Cookie技术。Cookie技术通过在请求和响应报文中写入Cookie信息来控制客户端状态。 没有Cookie信息状态下的客户端请求 第二次以后(存有Cookie信息状态)的请求 工作过程第一次客户端在没有Cookie信息状体下请求连接,请求报文类似如下 1234567891011//请求方法,URLRequest URL:http://localhost:7101/signupRequest Method:POST//请求首部字段Connection:keep-aliveContent-Type:application/x-www-form-urlencodedContent-Length:29Host:localhost:7101//首部字段中没有Cookie//内容实体(请求主体)name=admin3&password=22222222 第一次服务器端接收到HTTP请求报文时,产生Set-Cookie响应首部字段,通知客户端保存Cookie 12345678910111213//响应状态码Status Code:200 OK//响应首部字段Date:Mon, 20 Jun 2016 10:38:42 GMTContent-Length:9Content-Type:application/json; charset=utf-8//Set-Cookie响应首部字段Set-Cookie:BDSVRTM=132; path=/Set-Cookie:H_PS_PSSID=18286_1466_20317_18280_20368_20389_18134_17001_15371_11521; path=/; domain=.baidu.comSet-Cookie:__bsi=14590321692489225299_00_4_R_N_135_0303_C02F_N_I_I_0; expires=Mon, 20-Jun-16 13:49:06 GMT; domain=www.baidu.com; path=/Set-Cookie:BD_HOME=1; path=///响应主体{\"msg\":2} 客户端形成一个Cookie文本文件存储在客户端计算机的硬件或内存中客户端再次发送连接时,在HTTP请求报文的首部字段中添加Cookie信息并自动发送 123456789101112//请求方法,URLRequest URL:http://localhost:7101/signupRequest Method:POST//请求首部字段Connection:keep-aliveContent-Type:application/x-www-form-urlencodedContent-Length:29Host:localhost:7101//首部字段有CookieCookie:BAIDUID=02F58F2A65AE213FB82C3C963C00E28D:FG=1; BIDUPSID=02F58F2A65AE213FB82C3C963C00E28D; PSTM=1464940250; BDUSS=YwLS10dlN6U3hnaWEwbnVPU3VqTXgxVDV3TVlJWXhZQVY0amFRc0NPMkZ-SGxYQVFBQUFBJCQAAAAAAAAAAAEAAACM4OyLX9fT3sgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIVvUleFb1JXU1; pgv_pvi=2793529344; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; H_PS_645EC=bf0dy07frZ1UKtJW014QafgXKI2iO55SiuDpRwJWBb4nwVC2cp%2Fs31gktrj%2BAKcUUoi2; BD_CK_SAM=1; BD_HOME=1; H_PS_PSSID=18286_1466_20317_18280_20368_20389_18134_17001_15371_11521; BD_UPN=123253//内容实体(请求主体)name=admin3&password=22222222 提问: Cookie和Session到底有什么区别呢? HTTP报文内的HTTP信息本章节讲解请求和响应中的报文信息。 HTTP报文用户HTTP协议交互的信息被称为HTTP报文。客户端(请求端)的HTTP报文叫做请求报文,服务器端(响应端)的则叫做响应报文。HTTP报文大致可分为报文首部和报文主体两块。 报文首部: 服务器端或客户端需处理的请求或响应的内容及属性 CR+LF (回车 + 换行) 报文主体:应被发送的数据 报文结构请求报文 报文首部 请求行 请求首部字段 通用首部字段 实体首部字段 其他 空行(CR+LF) 报文主体 响应报文 报文首部 状态行 响应首部字段 通用首部字段 实体首部字段 其他 空行(CR+LF) 报文主体 说明 报文类型 说明 请求行 包含请求的方法,请求URI和HTTP版本 状态行 包含表明响应结果的状态码,原因短语和HTTP版本 首部字段 包含表示请求和响应的各种条件和属性的各类首部 其他 可能包含HTTP的RFC里未定义的首部 (Cookie)等 提示: 请求行示例:GET/HTTP/1.1。状态行示例:HTTP/1.1 200 OK。首部字段包含:通用首部、请求首部、响应首部和实体首部。 编码提升传输速率HTTP在传输数据时可以按照数据原貌进行传输,也可以在传输过程中通过编码提升传输速率。但是编码通过计算机来操作,需要消耗更多的CPU资源。 报文主体和实体主体的区别 报文: 是HTTP通信中的基本单位,由8bit字节流组成,通过HTTP通信传输。 实体:作为请求和响应的有效载荷数据被传输,由实体首部和实体主体组成。 通常报文的主体等于实体主体。只有编码操作时,实体主体的内容发生了变化,导致和报文主体产生了差异。 压缩传输的内容编码HTTP协议中有一种类似ZIP压缩文件功能的内容编码功能,该功能主要应用于实体内容,并保持实体内容原样压缩。内容编码后的实体由客户端接收并负责解码。 例如请求响应头部 1Accept-Encoding:gzip, deflate, sdch 常用内容编码方式: 1234gzip(GNU zip)compress (UNIX系统的标准压缩)deflate (zlib)identity (不进行编码) 分割发送的分块传输编码在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。把实体主体分块的功能功称为分块传输编码。 发送多种数据的多部分对象集合采用MIME(Multipurpose Internet Mail Extensions,多用途因特网邮件扩展)机制,允许邮件处理文本、图片、视频等多个不同类型的数据。 获取部分内容的范围请求传输图片时突然中断,如何在恢复后从之前的中断出恢复传输,而不是重新传输图片呢?要实现恢复传输就要指定下载的实体范围。指定范围的发送的请求叫做范围请求。例如对一份10000字节大小的资源,使用范围请求,可以只请求5001-10000字节内的资源。 5001-10000字节 1Range:bytes=5001-10000 5001字节之后的全部的 1Range:bytes=5001- 0-3000字节、5000-7000字节的多重范围 1Range:bytes=-3000,5000-7000 内容协商返回最合适的内容同一个Web网站有可能存在着多份相同内容的页面。比如英语版和中文版的Web页面。当浏览器默认的语言为英文或中文,访问相同的URI的Web页面时,会显示对应的英语版或中文版的Web页面。这种机制称为内容协商。 内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。例如 Accept Accept-Charset Accept-Encodeing Accept-Language Content-Language 内容协商有以下3种类型 服务器驱动协商:服务器端进行内容协商。 客户端驱动协商:由客户端进行内容协商的方式。 透明协商:服务器驱动和客户端驱动的结合体,各自进行内容协商的一种方法。 返回结果的HTTP状体码HTTP状态码负责表示客户端HTTP的请求的返回结果、服务器端处理是否正常、通知出现错误等工作。 状态码告知从服务器端返回的请求结果状态码由3位数字和原因短语组成,例如200 OK,数字中的第一位指定了响应类型,后两位无分类。状态码的类别如下: 数字 类别 原因短语1XX Information(信息性状态码) 接收的请求正在处理2XX Success(成功状态码) 请求正常处理完毕3XX Redirection(重定向状态码) 需要执行附加操作以完成请求4XX Client Error(客户端错误状态码) 服务器无法处理请求5XX Server Error(服务器错误状态码) 服务器处理请求出错 数字 类别 原因短语 1XX Information(信息性状态码) 接收的请求正在处理 2XX Success(成功状态码) 请求正常处理完毕 3XX Redirection(重定向状态码) 需要执行附加操作以完成请求 4XX Client Error(客户端错误状态码) 服务器无法处理请求 5XX Server Error(服务器错误状态码) 服务器处理请求出错 提示:HTTP状态码数量大概有60余种,实际上经常使用的大概只有十几种。 1XX 正在处理1XX响应结果表明请求已被接受,需要继续处理。 100 Continue客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。 101 Switching Protocols服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。 2XX 成功2XX响应结果表明请求被正常处理。 200 OK(常见)表示从客户端发来的请求在服务器端被正常处理了。例如: 1Status Code:200 OK 204 No Content仍然表明请求被服务器端正常处理,但在返回的响应报文中不含实体的主体部分。 206 Partial Content表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求。响应报文中包含了由Content-Range指定范围的实体内容。 3XX 重定向3XX响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。 301 Moved Permanently永久性重定向。如果请求的服务器资源被分配了新的URI(即修改了URI),以后就使用新的URI去指定服务器资源。比如,客户端保存了某个资源的URI作为书签,服务器端相对应资源的URI已经修改,则提醒客户端更新书签引用,从而客户端进行修改书签引用,此时就会产生301状态码。 提示:这里浏览器需要执行的特殊处理就是用新的URI去正确请求资源,如果有保存书签则更新书签。 302 Found临时性重定向。请求的资源被分配了新的URI,希望用户(本次)能使用新的URI访问。与301状态码功能类似,但是302表示临时性变更。比如用户把对应资源的URI保存成书签,但不会像301状态码出现时那样去更新书签。 提示:这里浏览器需要执行的特殊处理就是用新的URI去正确请求资源,但是如果有书签也不更新书签。 303 See Other该状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源。303状态码和302状态码有着相同的功能,但303明确表示客户端应采用GET方法获取资源。比如使用POST方法访问CGI程序,执行处理的结果是希望客户端能以GET方法重定向到另一个URI上去时,返回303状态码。虽然302状态码也可以实现实现相同的功能,但是这里使用303状态码更理想。 提示:很多现存的浏览器将302响应视为303响应,并使用GET方法访问在Location中规定的URI,而无视原先请求的方法。301、302、303响应状态返回时,几乎所有的浏览器都会把POST改成GET,并删除请求报文内的主体,之后请求会自动再次发送。301、302标准虽然是禁止将POST方法改变成GET的,但实际上大家都会这么做。 304 Not Modified(常见)客户端发送附带条件的请求时,服务器端允许请求访问资源,但因发生请求未满足条件的情况后,直接返回304(服务器资源未改变,可直接使用客户端未过期的缓存),304返回时,不包含任何响应的主体部分(所以加载很快,毕竟是本地缓存嘛!)。需要注意的是,304和重定向没有关系! 附带条件的类型(任意一个就行) If-Modified-Since If-None-Match If-Range If-Unmodified-Since 示例: 12If-Modified-Since:Mon, 28 Sep 2015 08:00:31 GMTIf-None-Match:\"809096666\" 307 Temporary Redirect临时重定向。该状态码和302 Found有着相同的含义。302标准禁止POST变换成GET,但是实际上大家并不遵守。307会遵照浏览器标准,不会从POST变成GET。 4XX 客户端错误4XX的响应结果表明客户端是发生错误的原因所在。 400 Bad Request400表示请求报文中存在语法错误,需修改请求内容后再次发送请求。 401 Unauthorized401表示发送的请求需要通过HTTP认证(BASIC认真、DIGEST认证)的认证信息。当浏览器初次接收到该状态响应时,会弹出认证用的对话窗口。 403 Forbidden403表明对请求资源的访问被服务器拒绝了,服务器可以不给出理由,如果想说明的话,可以在实体的主体部分给出详细理由说明。发生这种情况的原因可能是客户端并未获得服务器端文件系统的访问授权、访问权限出现某些问题(从未授权的的发送源IP地址进行访问)等。 404 Not Found(常见)404表明服务器上无法找到请求的资源。当然也可以在服务器端拒绝请求且不想说明理由时使用。 5XX 服务器错误5XX的响应结果表明服务器本身发生错误。 500 Internal Server Error (Express中常用)500表明服务器端在执行客户端的请求时发生了错误,也可能是服务器内部出了故障。 503 Service Unavailable503表明服务器暂时处于超负荷或正在进行停机维护,现在无法处理请求。 505 HTTP Version Not Supported服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。 小结状态码并不一定能正确表明响应状态,不少返回的状态码响应都是错误的,但是用户察觉不到。比如Web应用程序内部发生错误,状态码仍然返回200 OK。 与HTTP协作的Web服务器一台Web服务器可搭建多个独立域名的Web网站,也可作为通信路径上的中转服务器提升传输效率。 用单台虚拟机实现多个域名HTTP/1.1规范允许一台HTTP服务器搭建多个Web站点,因为利用了虚拟主机(虚拟服务器)的功能。客户端利用HTTP协议访问服务器时,会经常采用类似的www.hackr.jp这样的主机名和域名。域名通过DNS服务映射到IP地址(域名解析)后访问目标 网站。如果同一台服务器托管了不同的两个域名,使用DNS解析域后两者访问的IP地址会相同。 代理,网关,隧道HTTP通信时,除了客户端和服务器意外,还有一些用于通信数据转发的应用程序,例如代理,网关和隧道,它们可以配合服务器工作。这些应用程序和服务器可以请求转发给通信线路上的下一站服务器,并且能接收那台服务器发送的响应再转发给客户端。 代理具有转发功能,相当于客户端和服务器之间的中间人,接收到客户端发送的请求并转发给服务器,同时也可以接收服务器返回的响应并转发给客户端。 网关转发其他服务器的通信数据的服务器,接收从客户端发送来的请求时,可以从其他服务器上获取资源然后就像自己拥有资源的源服务器一样对请求进行处理。客户端可能都不知道自己的通信目标是一个网关。 隧道服务器和客户端如果非常远,可以使用隧道进行中转,并保持双方通信连接的应用程序。 代理 HTTP通信过程中,可级联多台代理服务器,转发时,需要附加Via首部字段以标记出经过的代理服务器信息。同时,通过设置组织内部的代理服务器可做到针对特定URI访问的控制。代理服务器的作用: 利用缓存技术减少网络带宽的流量 组织内部针对特定网站的访问控制 获取访问日志 代理有多种使用方法,一种是否使用缓存,一种是否会修改报文。 缓存代理代理转发响应时,缓存代理会预先将资源的副本缓存在代理服务器上,如果接收到相同资源的请求时,可以不从源服务器那里获取资源,将之前缓存的资源作为响应返回。 透明代理转发请求或响应时,不对报文做任何加工的代理类型被称为透明代理,反之被称为非透明代理。 网关 网关的工作机制和代理有点相似,但是网关能使通信线路上的服务器提供非HTTP协议服务。利用网关提高通信的安全性,可以在客户端和网关的通信线路上加密以确保连接的安全。 隧道 通过隧道的传输,可以和远距离的服务器安全通信,隧道本身是透明的,客户端不用在意隧道的存在。 保存资源的缓存缓存有两种,一种是保存在代理服务器上的资源副本,一种是在客户端本地磁盘内保存的资源副本。利用缓存可以节省通信流量和通信时间。缓存服务器是代理服务器的一种,归类为缓存代理类,当代理转发从源服务器返回的额响应时,代理服务器会保存一份资源的副本,如果下一次请求同样的资源,则直接由缓存服务器返回给客户端,而不是再次去请求源服务器。因此客户端可就近从缓存服务器上获取资源,而源服务器也不必多次处理相同的请求了。 缓存的有效期缓存的数据是有有效期的,不然源服务器更新了资源以后,仍然从缓存服务器获取数据则请求的将是’旧’资源了。所以会因为客户端的要求、缓存的有效期等因素,向源服务器确认资源的有效性。若判断了缓存失效,缓存服务器将从源服务器上获取’新’资源。 客户端的缓存缓存当然不仅仅可以缓存在代理服务器(缓存服务器)上,还可以存在客户端浏览器中。以IE程序为例,把客户端缓存称为临时网络文件。浏览器缓存有效,就不必再向服务器请求相同的资源了,可以直接从本地磁盘内读取。和缓存服务器相同的一点是,当判断缓存过期,会向源服务器确认资源的有效性,若判断浏览器缓存失效,浏览器会再次请求新资源。 HTTP首部HTTP协议的请求和响应报文中必定包含HTTP首部,只是平时用户在使用时感受不到它。 HTTP报文首部HTTP请求报文访问hackr请求报文示例: 1234567Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Encoding:gzip, deflate, sdchAccept-Language:zh-CN,zh;q=0.8Connection:keep-aliveHost:hackr.jpUpgrade-Insecure-Requests:1User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36 HTTP响应报文访问hackr响应报文示例: 12345678910Accept-Ranges:bytesConnection:closeContent-Encoding:gzipContent-Length:379Content-Type:text/htmlDate:Wed, 22 Jun 2016 10:33:28 GMTETag:\"45bae1-25e-4d2c3145df440\"Last-Modified:Tue, 08 Jan 2013 08:53:29 GMTServer:ApacheVary:Accept-Encoding,User-Agent HTTP首部字段HTTP首部字段传递重要信息使用首部字段是为了给浏览器和服务器提供报文主体大小、所使用的语言、认证信息等内容。比如浏览器可以告诉服务器只能解释中文,而服务器可以告诉浏览器多少时间后再过来访问。 HTTP首部字段结构首部字段由首部字段名和首部字段值构成,例如Content-Type用来表示报文主体的对象类型 1Content-Type:text/html 首部字段名 首部字段值Content-Type text/html 首部字段名 首部字段值 Content-Type text/html 首部字段值对应的单个HTTP首部字段可以有多个值,例如 1Accept-Encoding:gzip, deflate, sdch 提示:如果首部字段重复,则根据浏览器内部处理逻辑不通,结果可能并不一致,有些浏览器首先处理第一次出现的首部字段,有些则会优先处理最后出现的首部字段。 HTTP首部字段类型 首部字段类型 说明 通用首部字段 请求报文和响应报文都会使用的首部 请求首部字段 请求报文会使用的首部 响应首部字段 响应报文会使用的首部 实体首部字段 针对请求报文和响应报文的实体部分使用的首部 HTTP/1.1首部字段预览 通用首部字段 Cache-Control: 控制缓存的行为Connection:逐级首部、连接管理Date: 创建报文的日期时间Pragma:报文指令Trailer:报文末端的首部一览Transfer-Encoding:指定报文主体的传输编码方式Upgrade:升级为其他协议Via:代理服务器的相关信息Warning:错误通知 请求首部字段 Accept:用户代理可处理的媒体类型Accept-Charset:优先的字符集Accept-Encoding:优先的内容编码Accept-Language: 优先的语言Authorization:Web认真信息Host :请求资源所在服务器If-Modified-Since :比较资源的更新时间If-Range:资源未更新时发送实体Byte的范围请求Range:实体的字节范围请求User-Agent:HTTP客户端程序的信息 响应首部字段 Accept-Ranges :是否接受字节范围请求Age:推算资源创建经过时间ETag :资源的匹配信息Location:令客户端重定向至指定的URIServer:HTTP服务器的安装信息Vary :代理服务器缓存的管理信息 实体首部字段 Allow:资源可支持的HTTP方法Content-Encoding:实体主体的自然语言Content-Length:实体主体的大小(单位:字节)Content-Location :替代对应资源的URIContent-Range:实体主体的位置范围Content-Type:实体主体的媒体类型Expires :实体主体过期的日期时间Last-Modified:资源最后修改的日期时间 非HTTP/1.1首部字段比如Cookie、Set-Cookie等。 End-to-end首部和Hop-by-hop首部 端到端首部会转发给请求(响应)对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。 逐跳首部只对单次转发有效,会因通过缓存或代理而不再转发,HTTP/1.1和之后的版本如果要使用Hop-by-hop首部需提供Connection首部字段。 逐跳首部字段有以下8种,除了这些以外的都是端到端首部 Connection Keep-Alive Proxy-Authenticate Proxy-Authorization Trailer TE Transfer-Encoding Upgrade HTTP/1.1通用首部字段请求报文和响应报文双方都会使用的首部。 Cache-Control使用此首部可以操作缓存机制。参数可选,使用,分隔,示例如下 1Cache-Control:max-age=0,no-cache 缓存请求指令 指令参数 参数 说明 no-cache 无 强制向源服务器再次验证 no-store 无 不缓存请求(响应)的任何内容 max-age=[秒] 必需 响应的最大Age值 no-transform 无 代理不可更改媒体类型 only-if-cached 无 从缓存获取资源 缓存响应指令 指令 参数 说明public 无 可向任意方提供响应的缓存private 可省略 仅向特定用户返回省略no-cache 可省略 缓存前必须先确认其有效性no-store 无 不缓存请求(响应)的任何内容max-age=[秒] 必需 响应的最大Age值s-maxage=[秒] 必需 公共缓存服务器响应的最大Age值no-transform 无 代理不可更改媒体类型 指令参数 参数 说明 public 无 可向任意方提供响应的缓存 private 可省略 仅向特定用户返回省略 no-cache 可省略 缓存前必须先确认其有效性 no-store 无 不缓存请求(响应)的任何内容 max-age=[秒] 必需 响应的最大Age值 max-age=[秒] 必需 响应的最大Age值 s-maxage=[秒] 必需 公共缓存服务器响应的最大Age值 no-transform 无 代理不可更改媒体类型 能否缓存public 1Cache-Control:public 明确表明其他用户也可利用缓存。private 1Cache-Control:private 缓存服务器会对特定用户提供资源缓存的服务,对于其他用户发送过来的请求代理服务器不会返回缓存。 no-cache 1Cache-Control:no-cache 使用no-cache目的是防止从缓存中返回过期的资源。客户端发送请求如果包含该指令则表示客户端不会接收缓存过的响应。缓存服务器必须把客户端的请求转发给源服务器(强制向源服务器验证)。如果源服务器返回的响应包含该指令,那么缓存服务器不能对资源进行缓存,源服务器以后也不会对缓存服务器请求中提出的资源有效性进行确认,禁止对响应资源进行缓存操作。 提示:无参数的响应(源服务器发送的首部字段)首部字段可以在客户端使用缓存,不能在缓存服务器使用缓存。 1Cache-Control:no-cache=Location 如果对no-cache指定具体参数值,那么客户端在接收到这个被指定参数值得首部字段对应的响应报文后,就不能使用缓存,当然无参数的首部字段可以在客户端使用缓存。 提示:只能在响应指令中指定该指令的参数值。 控制可执行缓存的对象的指令no-store 1Cache-Control:no-store 暗示请求或响应中包含机密信息,规定缓存不能在本地存储请求或响应的任一部分。 提示: no-store是真正的不进行缓存,而no-cache代表不缓存过期的资源。 缓存期限和认证max-age 1Cache-Control:max-age=6000(单位是秒) 客户端发送请求中如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源,如果指定max-age为0,那么缓存服务器通常需要将请求转发给源服务器。而服务器返回的响应中包含max-age指令时,缓存服务器将不对资源的有效性再做确认,max-age数值代表资源保存为缓存的最长时间。 提示:HTTP/1.1缓存服务器遇到同时存在Expires首部字段的情况时,会优先处理max-age指令,而HTTP/1.0恰好相反。 s-maxage 1Cache-Control:s-maxage=6000(单位:秒) s-maxage指令的功能和max-age相同。不同点在于s-maxage指令只适用于提供多位用户使用的公共缓存服务器(代理服务器)。对于同一用户重复返回响应的服务器没有任何作用。 提示:使用s-maxage会忽略Expires和max-age。 min-fresh 1Cache-Control:min-fresh=60(单位:秒) 该指令要求缓存服务器返回至少还未过指定时间的缓存资源。如果指定60s,在这60s以内如果有超过有效期限的资源都无法作为响应返回。 must-revalidate 1Cache-Control:must-revalidate 代理会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理无法向源服务器再次获取有效资源的话,缓存必须给客户端一条504状态码。 no-transform 1Cache-Control:no-transform 无论请求还是响应,缓存不能改变主体的媒体类型。可防止缓存(代理)压缩图片等类似操作。 Connection 控制不再转发给代理的首部字段 管理持久连接 控制不再转发给代理的首部字段12Upgrade:HTTP/1.1Connection:Upgrade 在客户端发送请求和服务器返回响应内,使用Connection首部字段可控制不再转发给代理的首部字段。 管理持久连接1Connection:Keep-Alive HTTP/1.1默认都是持久连接的。以上是客户端请求响应时的持久连接首部信息。 1Connection:close 服务器想明确断开连接,则指定该首部字段的值为close。 Date1Date:Thu, 23 Jun 2016 06:19:55 GMT 该首部字段表明创建HTTP报文的日期和时间。 Pragma12Pragma:no-cacheCache-Control:no-cache 该首部字段是HTTP/1.1之前的版本遗留字段,为了向低版本的HTTP协议兼容,一般需要加上该字段,作用和Cache-Control:no-cache一样,虽然属于通用首部字段,但是只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源。为了兼容,一般会把两个首部字段都加上。 Transfer-Encoding1Transfer-Encoding:chunked 规定了传输报文主体时采用的编码方式。HTTP/1.1的传输编码方式对分块传输编码有效。 Upgrade12Upgrade:HTTP/1.1Connection:Upgrade 用于检测HTTP协议及其他协议是否可使用更高版本进行通信,参数也可以指定一个完全不同的通信协议。 12Upgrade:TLS/1.0Connection:Upgrade 必须这样捆绑使用,因为Upgrade首部字段产生的作用仅限于客户端和邻接服务器之间。 Via追踪客户端和服务器之间的请求和响应报文的传输路径。报文经过代理和网关时会先在首部字段Via中附加该服务器的信息,然后在进行转发。 Warning12Warning: [警告码] [警告的主机:端口号] \"[警告内容]\" ([日期时间])Warning: 113 gw.hacker.jp:8080 \"Heuristic expiration\" Tue,03 JUL => 2012 05:09:44 GMT 提示:警告码和含义可以查阅相关资料。 HTTP/1.1请求首部字段Accept1Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept首部字段可通知服务器用户代理能够处理的媒体类型及媒体类型的相对优先级。使用type/subtype形式,一次可以指定多种媒体类型。以下是媒体类型举例: 媒体类型 说明 文本文件 text/html,text/plain,text/css, application/xhtml+xml,application/xml… 图片文件 image/jpeg,image/gif,image/webp,image/png… 视频文件 video/mpeg,video/quicktime… 应用程序使用的二进制文件 application/octet-stream,application/zip… 使用q=可以表示要显示的媒体类型的权重值,用;分割,范围是0-1(可精确到小数点后三位),且1是最大值,默认权重值为1。客户端向服务器请求媒体数据时,当服务器可以提供多种媒体类型时,首先返回权重值最高的媒体类型。 Accept-Charset1Accept-Charset:iso-8859-5,unicode-1-1;q=0.8 用来通知服务器用户代理支持的字符集及字符集的相对优先顺序。 Accept-Encoding1Accept-Encoding:gzip,deflate 用来告知服务器用户代理支持的内容编码以及这些编码的优先级。 内容编码 说明 gzip 由文件压缩程序gzip(GNU zip)生成的编码格式(RFC1952),采用Lempel-Ziv算法(LZ77)及32位循环冗余校验(CRC) compress 由UNIX文件压缩程序compress生成的编码格式,采用Lmepel-Ziv-Welch算法(LZW) deflate 组成使用zlib格式及由deflate压缩算法生成的编码格式 identity 不执行压缩或不会变化的默认编码格式 提示:使用最多的当然是gzip编码格式,其次还有其他的一些编码格式例如sdch。 Accept-Language1Accept-Language:zh-CN,zh;q=0.8 告知服务器客户端能够处理的自然语言集(英文、中文等),可一次指定多种自然语言集。 Authorization告知服务器客户端(用户代理)的认证信息(证书值)。 Expect1Expect:100-continue 客户端使用首部字段Expect来告知服务器期望出现的某种特定行为。但是好像HTTP/1.1规范只指定了100-continue。 Host1Host:hackr.jp 首部字段告诉服务器请求资源所处的互联网主机名和端口号。Host首部字段在HTTP/1.1中是唯一一个必须被包含在请求内的首部字段。 if-Match12If-Match:12345If-Match:* (忽略ETag值,只要资源存在就处理请求) 条件请求之一(If-xxx),服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。只有当If-Match的字段值跟ETag值匹配一致时,服务器才会接受请求。 if-Modified-Since1If-Modified-Since:Tue, 08 Jan 2013 08:53:29 GMT 告知服务器,若if-Modified-Since的字段值早于资源的更新时间,则希望能处理该请求。如果在指定if-Modified-Since字段值的日期时间之后,资源都没有更新,则返回状态码304 Not Modify。 if-Modified-Since的时间 < 资源更新的时间 = 返回新资源否则资源未更新过则返回状态码304 Not Modify。 if-Modified-Since用于确认代理和客户端拥有的本地资源的有效性,获取资源的更新日期时间,可通过首部字段Last-Modified来确定。 if-None-Match与If-Match作用相反,不匹配ETag值时才会接受请求。 if-Range12If-Range:\"123445\"Range:bytes=5001-10000 告知服务器若指定的If-Range字段值(Etag值或者时间)和请求资源的Etag值或时间相一致时,则作范围请求处理。反之,返回全体资源。 if-Unmodified-Since与if-Modified-Since作用相反。 Max-Forwards以十进制整数形式指定可经过的服务器最大数目。当值为0时,则不再进行转发,必须直接返回响应。此值在跟踪通信过程时非常有用,比如要途径多个转发服务器时,转发失败,客户端就很难得到服务器返回的响应了,而且我们也不知道是哪个代理服务器出了问题,此时可以设定Max-Forwards值来初定了解传输路径的通信情况。需要注意的是该值没经过一个代理服务器自减1,如果值为0则不再转发,必须强制返回响应。 Proxy-Authorization接收到从代理服务器发来的认证质询时,客户端会发送包含首部字段Proxy-Authorization的请求,告知服务器认证所需要的信息。 Range1Range:bytes=5001-10000 范围请求时告知服务器资源的指定范围。如果请求成功,则返回206状态码,无法处理该范围请求时,返回200及全部资源。 TE1TE:gzip,deflate;q=0.5 告知服务器客户端能够处理响应的传输编码方式及相对优先级。和Accept-Encoding的功能很像,但是用于传输编码。 User-Agent1User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36 告诉服务器创建请求的浏览器和用户代理的名称,中间可能会被添加上代理服务器的名称。 HTTP/1.1响应首部字段Accept-Ranges12Accept-Ranges:bytesAccept-Ranges:none 告诉客户端是否能处理范围请求,none指明不能处理,bytes指明处理成功。 Age1Age:600(单位:秒) 告诉客户端源服务器多久前创建了响应。 ETag1ETag:\"4324hkh23h4h34fdhs4732hfadsjk\" ETag告知客户端实体标识,它是将资源以字符串形式做唯一性标识的方式,服务器会为每份资源分配对应的ETag值,资源更新时,ETag值也会更新。若在下载过程中出现连接中断、再连接的情况,都会按照ETag值来指定资源。 提示:ETag值有强弱之分。 Location1Location:http://www.ziyi2.cn/index.html 可以将响应接收方引导至某个与请求URI位置不同的资源。该字段会配合3xx:Redirection的响应,提供重定向URI。即服务器端如果将需要访问的资源转移到一个新的URI后,客户端发起请求,服务器就会返回一个带Location字段的响应通知客户端重定向到新的URI,通常客户端在接收到这个字段时都会强制性的尝试对已提示的重定向资源进行访问。 Proxy-Authorizaticate注意与请求响应的首部字段名Proxy-Authorization是配合起来使用的,该字段是会把代理服务器要求的认证信息发送给客户端。 Retry-After告诉客户端多久之后再次发送请求。可以具体指定日期或者创建响应后的秒数。 Server1Server:Apache/2.2.17(Unix) 告知客户端当前服务器上安装的HTTP服务器应用程序的信息。可能还会标出服务器的版本号和安装时启动的可选项。 Vary1Vary:Accept-Encoding,User-Agent 对缓存进行控制,源服务器向代理服务器传达关于本地缓存使用方法的命令就是Vary字段,当客户端发起请求时,只对Vary指定的请求首部相同的HTTP请求(HTTP请求报文中的对应首部字段名和字段值和Vary中指定的一样),才会返回缓存。如果不同,那么将从源服务器重新获取资源。 WWW-Authenticate用于HTTP访问认证。会告诉客户端适用于访问请求URI所指定资源的认证方案(Basic或Digest)。 HTTP/1.1实体首部字段请求实体和响应实体都会含有一些信息,所以在请求报文和响应报文要加入相关实体部分信息的首部字段。 Allow1Allow:GET,HEAD 用于通知客户端能够支持Request URL指定资源的所有Request Method方法(HTTP请求方法)。如果服务器接收都不支持的HTTP方法,会以状态码405 Method Not Allowed作为响应返回,还会把所有支持的方法写入Allow首部字段返回。 Content-Encoding1Content-Encoding:gzip 告知服务器对实体的主体部分选用的内容编码方式。 Content-Language告知客户端实体主体使用的自然语言。 Content-Length实体主体部分的大小(单位是Byte)。 Content-Location报文主体返回资源相对应的URI。 Content-MD5服务器端返回资源时,会对报文主体进行MD5算法,接着进行Base64编码,客户端会对接收到的报文主体进行同样的算法,从而得出一个128bit的二进制数,如果该数一样,则表明报文主体传输过程完整。其实起到的是一个校验的作用。 Content-Range1Content-Range:bytes 5001-10000/10000 针对范围请求,返回资源时告诉客户端作为响应返回的实体的哪个部分符合范围请求。 Content-Type1Content-Type:text/css; charset=utf-8 说明实体主体对象的媒体类型。 Expires将资源失效的日期告知客户端。缓存服务器接收到含有该字段的响应后,会缓存来应答请求,在Expires指定的时间之前,响应的副本会一直被保存,超过指定的时间后,缓存服务器在请求发送过来时,会转向源服务器请求资源。 Last-Modified指明资源最终修改的时间,指定的是Request URL指定资源被修改的时间。 为Cookie服务的首部字段Cookie的工作机制是用户识别及状态管理。调用Cookie时可校验有效期、发送方的域、路径、协议等信息,所以正规发布的Cookie内的数据不会因来自其他Web站点和攻击者的攻击而泄露。 首部字段名 说明 首部类型 Set-Cookie 开始状态管理所使用的cookie信息 响应首部字段 Cookie 从服务器接收到的Cookie 请求首部字段 Set-Cookie1234Set-Cookie:BDSVRTM=123; path=/Set-Cookie:H_PS_PSSID=18286_1466_20317_18280_20368_20389_19690_18134_17001_15371_11521; path=/; domain=.baidu.comSet-Cookie:__bsi=17382622087912227414_00_8_N_N_125_0303_C02F_N_N_Y_0; expires=Thu, 23-Jun-16 09:32:01 GMT; domain=www.baidu.com; path=/Set-Cookie:BD_HOME=1; path=/ 当服务器准备开始管理客户端的状态时,会事先告知各种信息。 属性 说明 NAME=VALUE 赋予Cookie的名称和其值(必需项) expires = DATE Cookie的有效期(若不明确指定则默认为浏览器关闭前为止) path = PATH 将服务器上的文件目录作为Cookie的适用对象(不指定则默认在文档所在的文件目录) domain = 域名 作为Cookie适用对象的域名(若不指定则默认为创建Cookie的服务器域名) Secure 仅在HTTPS安全通信时才会发送Cookie HttpOnly 加以限制,使Cookie不能被JavaScript脚本访问 expires属性指定浏览器可发送的Cookie的有效期。当省略expires属性时,其有效期仅限于维持浏览器会话(Session)时间段内。通常限于浏览器应用程序被关闭之前。一旦Cookie从服务器送至客户端,服务器端就不存在可以显示删除Cookie的方法了,但是可通过覆盖过期的Cookie实现对客户端Cookie的实质性删除操作。 path属性Cookie的path属性可用于限定指定Cookie的发送范围的文件目录。不过有办法避开这项限制。 domain属性通过Cookie的domain属性指定的域名可做到与结尾匹配一致,比如,指定example.com后,除了example.com外,www.example.com和www2.example.com都可以发送Cookie。除非针对指定的多个域名发送Cookie之外,不指定domain更为安全。 secure属性用于限制Web页面仅在HTTPS安全连接时,才可以发送Cookie。使用方法如下: 1Set-Cookie:BDSVRTM=123; path=/; secure 以上例子只在https://www.example.com/(HTTPS)安全连接的情况下才会进行Cookie的回收。即使域名相同,http://www.example.com/也不会发生Cookie回收行为。省略该参数,HTTP和HTTPS都可以进行回收。 HttpOnly属性该属性是Cookie的扩展功能,使JavaScript脚本无法获得Cookie。主要目的是为了防止跨站脚本攻击(Cross-site scripting,XSS)对Cookie信息的获取。指定方法如下: 1Set-Cookie:BDSVRTM=123; path=/; HttpOnly 通过以上设置,通常从Web页面还可以对Cookie进行读取操作,但是使用JavaScript的document.cookie就无法读取附加该属性后的Cookie内容了。所以在无法再XSS中利用JavaScript劫持Cookie。 Cookie告知服务器,客户端想要获得HTTP状体管理支持时,就会在请求中包含从服务器接收到的Cookie,接收到多个,就可以以多个的形式发送。 其他首部字段HTTP首部字段是可以自行扩展的,所以在Web服务器和浏览器的应用上会出现各种非标准的首部字段。 X-Frame-Options1X-Frame-Options:DENY 属于响应首部,控制网站内容在其他Web网站的Frame标签内的显示问题。目的是为了防止点击劫持攻击。 DENY:拒绝 SAMEORIGIN:仅在同源域名下的页面匹配时许可(比如http://hackr.jp/sameple.html页面为SAMEORIGIN时,那么hackr.jp上所有页面的frame都被允许可加载该页面,而example.com等其他域名就不被允许了)。 并不是所有浏览器都支持该首部,当然主流的浏览器一般都能支持。 提示:一般在HTTP协议中,给非标准参数加上前缀X-,用来区别标准参数。 X-XSS-Protection属于响应首部,这对跨站脚本攻击(XSS)的一种策略,用于控制浏览器XSS防护机制的开关。 0:将XSS过滤设置成无效状态 1:将XSS过滤设置成有效状态 DNT1DNT:1 HTTP请求首部,意思是Do Not Track,拒绝个人信息被收集,表示拒绝被精准广告追踪的一种方法。 0:同意被追踪 1:拒绝被追踪 确保Web安全的HTTPS在HTTP协议中有可能存在信息窃听或身份伪装等安全问题,使用HTTPS通信机制可以有效的防止这类问题。 HTTP缺点 通信使用明文(不加密),内容可能被窃取 不验证通信身份,容易遭遇伪装 无法证明报文的完整性,可能遭篡改 通信使用明文HTTP报文使用明文(通信的请求和响应的内容未经过加密处理)方式发送。 TCP/IP是可能被窃听的网络互联网上的任何角落都存在通信内容被窃听的风险,包括客户端、代理服务器、互联网和源服务器等。只要收集来互联网上流动的数据帧就可以了,这些工作可以通过抓包(Packet Capture)嗅探器(Sniffer)工具,例如抓包工具( Wireshark)。例如查看发送的请求和返回的响应,以及响应报文的全部内容等一系列事情都可以做到。 加密处理防止被窃听 通信的加密HTTP协议本身没有加密机制,可以使用SSL(Secure Socket Layer,安全套接层)或TLS(Transport Layer Security,安全传输层协议)的组合使用,加密通信内容。用SSL建立安全通信线路之后,就可以在这条线路上进行HTTP通信了。使用SSL组合使用HTTP被称为HTTPS(HTTP Secure,超文本传输安全协议)或HTTP over SSL。 内容的加密对传输的HTTP报文中的内容主体加密(不对报文首部加密)。为了做到内容加密,客户端和服务器需要同时具备加密和解密机制。但是不同于SSL或TLS将整个通信线路加密处理,内容仍然有被篡改的风险。不验证通信身份 HTTP协议中的请求和响应不会对通信方进行确认,不验证请求的客户端和返回响应的服务器。 任何人都可以发起请求HTTP协议的实现本身非常简单,不论是谁发送过来的请求都会返回响应(当然前提是发送端的IP地址和端口号没有被Web服务器设定限制访问的前提下)。 无法确认请求的那台服务器是否是伪装的Web服务器。 无法确认返回响应的客户端是否是伪装的客户端。 无法判定请求是谁。 无意义的请求也会照单全收,无法阻止海量请求下的Dos攻击(Denial Of Service,拒绝服务攻击)。 查明对手的证书 使用SSL则可以确定通信方。SSL不仅提供加密处理,还使用了证书手段,用于确定方。证书由第三方机构颁发,难以伪造,通过使用证书,客户端可以完成个人身份的确认,也可用于对Web网站的认证环节。 无法证明报文的完整性即无法确认报文信息的准确度。 接收到的内容可能有误无法确认发出的请求和接收到的响应是前后一致的,比如从服务器下载文件,在响应过程的中途可能遭到篡改,而使得下载的文件是篡改后的文件而不是原来需要的源服务器上的文件。这种在传输中途遭到攻击拦截并篡改内容的攻击称为中间人攻击(Man-in-the-Middle attack,MITM)。 防止篡改有确定报文完整性的方法,例如使用MD5和SHA-1等散列值校验方法,以及提供文件下载服务的Web网站也会提供相应的PGP(Pretty Good Privacy,完美隐私)创建数字签名和MD5算法生成散列值,但是算法本身也有可能被篡改,用户是意识不到的,所以HTTP本身很难确保报文的完整性,有必要使用HTTPS,毕竟SSL提供认证和加密处理功能。 HTTPSHTTP + 加密 + 认证 + 完整性保护HTTP协议中使用未经过机密的明文,比如在Web页面中输入信用卡号,如果通信线路遭到窃听,那么信用卡号就暴露了!另外,HTTP协议无法确认通信方,无论是客户端还是服务器,所以需要使用在HTTP基础上添加加密及认证机制的HTTP(HTTP Secure, HTTPS)。使用HTTPS通信时,使用的是https://而不是http://(通常会在登录页面和购物车结算页面使用)。 HTTP 披上外壳SSLHTTPS并非是应用层的一种新协议。只是HTTP通信接口部分用SSL和TLS协议代替而已。应用层HTTP通常一般直接和传输层的TCP通信,而HTTPS则是使应用层HTTP先和SSL通信,再由SSL和TCP通信。 HTTP 应用层 HTTP 传输层 TCP 网络层 IP HTTPS 应用层HTTP 表示层SSL 传输层TCP 网络层IP SSL是独立于HTTP的协议,与其他协议也可以配合使用的,可以说SSL是目前使用最广泛的网络安全技术。 加密技术SSL采用一种公开密钥加密的加密处理方式。加密和解密都会用到密钥,没有密钥就无法对密码解密。 共享秘钥加密加密和解密同用一个秘钥的方法称为共享秘钥加密或者对称秘钥加密。这种方法需要把秘钥发送给对方,比如客户端需要和服务器通信加密,需要把秘钥发送给服务器(毕竟用同一个秘钥嘛),转发秘钥时如果通信被监听秘钥就会被攻击者获取。 使用两把秘钥的公开秘钥加密公开秘钥加密使用一对非对称的秘钥,一把叫做私有秘钥,一把叫做公开秘钥。私有秘钥不能让任何人知道,公开秘钥任意人都可以获取。发送密文的一方使用对方发送过来的公开秘钥进行加密处理(比如要实现加密,服务器先给客户端发送一个公开秘钥),对方接收到加密后的信息时,再使用自己的配套公开秘钥的私密秘钥进行解密(客户端发送了按照公开秘钥加密的报文,服务器使用对应的私有秘钥进行解密工作)。这种方式根本不需要担心公开秘钥被窃听。同时根据公开秘钥和密文对信息原文进行解密也是异常困难的。 HTTPS采用混合加密机制HTTPS采用共享秘钥加密和公开秘钥加密混合使用加密机制。因为后者与前者相比,处理速度要慢,所以在能够实现安全通信的情况下,使用共享秘钥加密。 使用公开秘钥加密的机制传送稍后需要用到的共享秘钥加密的秘钥。 建立通信后交换报文阶段则使用共享秘钥加密方式。 证明公开秘钥正确性的证书怎么证明公开秘钥本身又是货真价实的公开秘钥呢?例如如何证明客户端接收到的公开秘钥是对应的服务器发行的公开秘钥?因为公开秘钥也容易被攻击者劫持啊。此时可以使用数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开秘钥证书。需要注意的是数字证书认证机构是需要客户端和服务器双方都可信任的第三方机构。 提示:注意区分机构的私有秘钥和服务器的公有秘钥,机构的私有秘钥用来加密数字签名,服务器的公有秘钥最终是为了进行和客户端通信时可以使用公开秘钥加密的加密机制。公钥证书包含服务器提交的公开秘钥和数字证书机构认证的数字签名。 验证服务器公开秘钥的正确性:客户端拿到公钥证书后,使用数字证书认证机构的公开秘钥对数字签名进行解密,验证服务器公开秘钥的真实性,如果正确,则使用服务器提出的公开秘钥对报文进行加密传输。解密过程:接收到客户端发送的加密报文后,使用服务器对应的私有秘钥进行解密操作。 秘钥类型 作用 服务器公开秘钥 通信时加密用 服务器私有秘钥 通信时解密用 认证机关的私有秘钥 向服务器提交的公开秘钥部署数字签名 认证机关的公开秘钥 在客户端验证服务器公开秘钥的正确性 提示:认证机关的公开秘钥必须安全的转交给客户端,通常多数浏览器开发商发布版本时,事先在内部植入常用认证机关的公开秘钥。 可证明组织真实性的EV SSL证书EV SSL证书严格规定了对运营组织是否真实的确认方针,可以防止用户被钓鱼攻击。 用以确认客户端的客户端证书HTTPS还可以使用客户端证书。以客户端证书进行客户端认证。例如银行的网上银行就是采用客户端证书,在登录网银时不仅要求用户确认输入的ID和密码,还会要求用户的客户端证书,以确认用户是否从特定的终端访问网银。 认证机构信誉第一如果认证结构被黑,那么SSL的可信度? 由自认证机构颁发的证书称为自签名证书该证书容易被认定是伪造的证书,没有什么大用?HTTPS的安全通信机制 HTTPS通信步骤 提示: master Secret是报文校验码的秘钥。 SSL和TLSHTTPS使用SSL和TLS这两个协议。SSL最初由浏览器开发商网景通信公司率先倡导的。TLS则是以SSL为原型(SSL3.0为基准)开发的协议。有时统一称该协议为SSL。 SSL速度慢HTTPS使用SSL时,处理速度会变慢。因为需要做服务器、客户端双方的加密和解密处理,会消耗CPU和内存等硬件资源。和HTTP通信相比,SSL通信又在TCP通信之上建立了一层握手通信,消耗网络资源,时间上延长了。和HTTP通信相比,网络负载可能会慢2-100倍。解决办法是可以使用SSL加速器(专用服务器)硬件来提高SSL的计算速度。小结 为什么不一直使用HTTPS通信呢?一方面是某些信息并不敏感,例如网页的呈现等,可以使用HTTP通信,并且加载速度比HTTPS也要快(网络负载更少),只有在获取和提交某些敏感信息时才需要使用HTTPS通信。 确认访问用户的认证某些Web页面只想让特定的人浏览,比如网上银行,或者干脆仅本人可见。为达到这个目的,必不可少的就是认证功能。 何为认证计算机本身无法判断坐在显示器前的使用者的身份。为了知道谁在访问服务器,需要让客户端自报家门,通常核对客户端身份的信息有如下几种: 密码 动态令牌 数字证书 生物认证 IC卡等 HTTP的认证方式HTTP/1.1使用的认证方式如下所示: BASIC认证(基本认证) DIGEST认证(摘要认证) SSL客户端认证 FormBase认证(基于表单认证) BASIC认证BASIC认证(基本认证)是从HTTP/1.0就定义的认证方式。Web服务器与通信客户端之间进行的认证方式。 提示:401 Authorization Required首部字段值还包含了认证方式BASIC。 BASIC认证虽然采用Base64编码方式,但仍然是不加密处理的,在HTTP等非加密通信的线路上进行BASIC认证的过程中,很容易被人窃听。所以BASIC认证的安全性还不够高。 DIGEST认证为了弥补BASIC认证存在的弱点,从HTTP/1.1起就有了DIGEST认证。该认证同样使用质询/响应的方式,但不会像BASIC认证那样直接发送明文密码。 SSL客户端认证从使用用户ID和密码的认证方式方面来讲,只要二者内容正确一致,就可认证是本人操作,但是如果用户的账号和密码被窃取,很有可能是第三者冒充。利用SSL客户端认证则可以避免这个情况。SSL客户端认证是由HTTPS的客户端证书完成认证的方式。凭借客户端证书认证,服务器可确认访问是否来自已登录的客户端。 客户端认证步骤步骤一:接收认证资源的请求,服务器发送Certificate Request报文,要求客户端提供客户端证书。步骤二:用户选择将发送的客户端证书后,客户端会把客户端证书信息以Client Certificate报文方式发送给服务器。步骤三:服务器验证客户端证书验证通过后可领取证书内客户端的公开秘钥,然后开始HTTPS加密通信。 提示: 为了进行SSL客户端认证,需要事先安装客户端证书。 SSL客户端认证采用双因素认证SSL客户端认证不仅依靠证书完成认证,还会和基于表单认证组合形成一种双因素认证。第一个认证因素是SSL客户端证书用来认证客户端计算机,第二个认证因素的密码来确定是用户本人的行为。 基于表单认证基于表单的认证方法并不是HTTP协议中定义的。客户端会向服务器上的Web应用程序发送登录信息,按登录信息的验证结果认证。 认证多半是基于表单认证BASIC认证和DIGEST认证因为使用上的便利性和安全性几乎不怎么使用,基于SSL的客户端认证虽然具有高度的安全性,但因为导入及维持费用等问题,还尚未普及。对于Web网站认证功能,能够满足其安全使用级别的标准规范并不存在,所以只好使用由Web应用程序各自实现基于表单的认证方式。 Session管理及Cookie应用基于表单认证的标准规范尚未有定论,一般会使用Cookie来管理Session。基于表单认证本身是通过服务器端的Web应用,将客户端发送过来的用户ID和密码与之前登陆过的信息做匹配来进行认证的。但是HTTP是无状态协议,之前已认证成功的用户状态无法通过协议层面保存下来,HTTP无法实现状态管理。因此即使当该用户的下一次继续访问,也无法区分他与其他用户。于是我们会使用Cookie来管理Session,以弥补HTTP协议中不存在的状态管理功能。 步骤一:客户端把自己的ID和密码等登录信息收入报文的实体部分,通常是以POST方法把请求发送给服务器。这时会使用HTTPS通信来进行HTML表单画面的显示和用户输入数据的发送。步骤二:服务器会发放用以识别用户的Session ID。通过验证客户端发送过来的账号和密码,然后把用户的认证状态与Session ID绑定后记录在服务器端。向客户端返回响应时,会在首部字段Set-Cookie内写入Session ID(如Set-Cookie:PHPSESSID=028a8c…)。可以把Session ID想象成用以区分不同用户的等位号,然而如果Session ID被第三方盗走,对方就可以伪装成你的身份进行操作了,因此必须防止Session ID被盗,或被猜出。一般Session ID使用难以推测的字符串,且服务器端也需要进行有效期的管理,保证其安全性。另外为减轻跨站脚本攻击(XSS),建议事先给Cookie加上httponly属性。步骤三:客户端接收到从服务器端发来的Session ID后,会将其作为Cookie保存在本地。下次向服务器发送请求时,浏览器会自动发送Cookie,所以Session ID随之发送到服务器,服务器可通过验证接收到的Session ID识别用户和其认证状态。 不仅表单认证的登录信息及认证过程没有标准化的方案,服务器端应如何保存用户提交的密码等登录信息也没有被标准化。通常一种安全的保存密码方法是先利用密码加盐(salt)的方式增加额外信息,在使用散列值(hash)函数计算出散列值后保存,而不要直接保存明文密码,容易导致密码泄露。 提示:加盐就是由服务器随机生成一个字符串,长度足够长,并且是真正随机生成的,把它和密码字符串相连接(前后都可以)生成散列值。当两个用户使用了同一个密码时,由于随机生成的salt值不同,对应的散列值也将是不同的,很大程度上减少了密码特征,攻击者也很难破解。 基于HTTP的功能追加协议随着互联网的快速发展,HTTP协议在功能上已经捉襟见肘,本章讲解基于HTTP新增功能的协议。 SPDYGoogle在2010年发布了SPDY(取自SPeeDY,发音同speedy),目标旨在解决HTTP性能瓶颈,缩短Web页面的加载时间(50%)。 HTTP瓶颈一条连接只能发送一个请求请求只能从客户端开始,客户端不可以接收除响应以外的指令请求/响应首部未经过压缩就发送,首部信息越多延迟越大发送冗长的首部,每次发送相同的首部造成浪费颇多可任意选择数据压缩格式,非强制压缩发送 Ajax解决方法Ajax(Asynchronous JavaScript and XML,异步JavaScript与XML技术)是一种有效利用JavaScript和DOM(Document Object Model,文档对象模型)的操作,以达到局部Web页面替换加载的异步通信手段。由于更新一部分页面而不是全部页面,响应中传输的数据量会少很多,优点显而易见。Ajax的核心技术是名为XMLHttpRequest的API,通过JavaScript脚本语言的调用就能和服务器进行HTTP通信,从而能从加载完毕的Web页面发起请求,只更新局部页面。利用Ajax实时的从服务器获取内容,有可能导致大量的请求产生,另外Ajax仍未解决HTTP协议本身存在的问题。 Comet解决方法一旦服务器有内容更新,Comet不会让请求等待,而是直接给客户端返回响应。通过延迟应答,模拟实现服务器端向客户端推送的功能。 通常服务器端接收到请求,在处理完毕后会立即返回响应,但为了实现推送功能,Comet会先将响应置于挂起状态,当服务器端有内容更新时,再返回该响应。因此一旦服务器端有更新,就可以立即反馈给客户端。内容上虽然能够做到实时更新,但是为了保留响应,一次连接的持续时间也变长了,为了维持连接会消耗更多的资源,另外Comet仍未解决HTTP协议本身存在的问题。 SPDY目标陆续出现的Ajax和Comet等提高易用性的技术,使HTTP得到了部分改善,但HTTP协议本身的限制仍然未解决,SPDY协议正在HTTP协议层面进行持续开发,为了消除HTTP瓶颈。 SPDY设计与功能 应用层HTTP 会话层SPDY 表示层SSL 传输层TCP SPDY在HTTPS的基础上新增了会话层,仍然采用HTTP建立通信连接,可照常使用HTTP的GET和POST等方法,Cookie以及HTTP报文等。使用SPDY后,HTTP协议额外获得功能: 多路复用流通过单一的TCP连接,可以无限制处理多个HTTP请求,所有请求的处理都在一条TCP连接上完成,TCP处理效率得到提高。 赋予请求优先级可以为请求分配优先级顺序,在发送多个请求时,解决因宽带而导致响应变慢的问题。 压缩HTTP首部 推送功能Comet技术支持服务器主动向客户端推送数据。 服务器提示功能 SPDY性能SPDY只是将单个域名(IP地址)的通信多路复用,在Web网站使用多个域名下的资源,改善效果就会受到限制,但是SPDY的确是一种可有效消除HTTP瓶颈的技术。 使用浏览器进行全双工通信的WebSocket通信使用HTTP协议,无法彻底解决HTTP瓶颈问题,WebSocket网络技术正是解决问题而实现的一套新协议及API。当时筹划的WebSocket将作为HTML5的一部分,而现在它却逐渐变成了独立的协议标准。 WebSocket的设计与功能WebSocket是Web浏览器与Web服务器之间全双工通信标准。其中WebSocket协议由IETF定位标准,WebSocket API由W3C定位标准。WebSocket目前主要是为了解决Ajax和Comet里XMLHttpRequest附带的缺陷所引起的问题。 WebSocket协议一旦Web服务器与客户端之间建立了WebSocket协议的通信连接,之后所有的通信都依靠这个专用协议进行。可以在通信过程中互相发送JSON、XML、HTML或图片等任意格式的数据。由于是建立在HTTP基础上的协议,因此连接的发起方仍然是客户端,而一旦确立WebSocket通信连接,不论服务器和客户端,任意一方都可以直接向对方发送报文。 而不是传统的HTTP协议必须是客户端发起请求,服务器给出请求的响应。 推送功能支持由服务器向客户端推送数据的推送功能。这样服务器可以直接发送数据而不是等待客户端的请求。 减少通信量只要建立起WebSocket连接,就希望一直保持连接状态。和HTTP协议相比,不但每次连接时的总开销减少,而且由于WebSocket的首部信息很小,通信量也相对减少。 握手为了实现WebSocket通信,在HTTP连接建立后,只需要完成一次握手的步骤。 握手请求为了实现WebSocket通信,需要用到HTTP的Upgrade首部字段,告知服务器通信协议发生改变,已达到握手的目的。 1234567Request Method:GETHost:server.example.comUpgrade:websocketConnection:UpgradeSec-WebSocket-Key:fajdsfjewruewuiorueqworreioq==Sec-WebSocket-Protocol:chat,superchatSec-WebSocket-Version:13 Sec-WebSocket-Key字段记录着握手过程中必不可少的键值。Sec-WebSocket-Protocol字段记录使用的子协议。 握手响应对于之前的请求,返回状态码101 Switching Protocols的响应。 12345Status Code:101 Switching ProtocolsUpgrade:websocketConnection:UpgradeSec-WebSocket-Accept:fsfjlsdjfjds42fasfs3fsdfj==Sec-WebSocket-Protocol:chat Sec-WebSocket-Accept字段值是由握手请求中的Sec-WebSocket-Key字段值生成的。如果成功握手确立WebSocket连接之后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧。 WebSocket是全双工通信,因此服务器端不必等待请求,可直接发送数据,从而实现服务器端推送功能。 提示:当HTTP握手动作结束时,浏览器和服务器之间就形成了一个快速通道,当然从WebSocket名字也可以理解这个快速通道类似于Socket连接,客户端和服务器端就可以通过TCP连接直接交换数据了,快速通道连接一直持续到客户端或服务器端的某一方主动的关闭连接。所以WebSocket本质上是一个基于TCP的协议。 WebSocket APIJavaScript可调用WebSocket API内提供的WebSocket程序接口,以实现WebSocket协议下的全双工通信。 1var webSocket = new WebSocket(url,[subProtocol]); //创建一个WebSocket对象 提示:url是指定连接的URL,subProtocol是可选的子协议。 WebSocket事件 事件 事件处理程序 说明 open webSocket.onopen 连接建立时触发 message webSocket.onmessage 客户端接收服务端数据时触发 error webSocket.onerror 通信发生错误时触发 close webSocket.onclose 连接关闭时触发 WebSocket方法 send():使用连接发送数据close(): 关闭连接 WebSocket属性 属性 说明 Socket.readyState 表示连接状态 Socket.bufferedAmount 只读属性,表明已经被send()放入发送等待列表但是还没有发出的UTF-8文本字节数 客户端使用示例: 123456789101112131415161718192021222324function WebSocketExample(data){ if(\"WebSocket\" in window){ //检验浏览器是否支持WebSocket()接口 var ws = new WebSocket(ws://localhost:7070/echo) //创建一个WebSocket对象 /*连接建立*/ ws.onopen = function(){ if(ws.bufferedAmount === 0){ //如果发送等待列表是空,则可以继续发送数据 ws.send(data); } } /*接收数据*/ ws.onmessage = function(event){ var receiveData = event.data; } /*关闭连接*/ ws.onclose = function(){ alert(\"连接关闭!\"); } /*连接错误*/ ws.onerror = function(err){ } }else { alert(\"该浏览器不支持WebSocket连接!\"); }} HTTP/2.0回顾一下HTTP的发展历史: HTTP/0.9已经过时,只接受GET一种请求方法,没有在通讯中指定版本号,且不支持请求头,由于该版本不支持POST方法,所以客户端无法向服务器传递太多信息。 HTTP/1.0在通讯中指定版本号的HTTP协议,至今仍被广泛使用,特别是在代理服务器中。 HTTP/1.1与HTTP/1.0相比,主要区别在于 缓存处理 带宽优化及网络连接的使用 错误通知的管理 消息在网络中发送 互联网地址维护 安全性及完整性 目前主流的HTTP/1.1标准,在SPDY和WebSocket出现以后,很难断言仍是适用于当下的Web的协议。于是负责互联网技术标准的IETF(Internet Engineering Task Force,互联网工程任务组)创立了httpbis工作组,目标是推进下一代HTTP(HTTP/2.0)。 HTTP/2.0特点 SPDY HTTP Speed + Mobility Network-Friendly HTTP Upgrade HTTP Speed + Mobility由微软公司起草,用于改善提高移动端通信时通信速度和性能的标准。建立与Google公司提出的SPDY与WebSocket的基础之上。 HTTP/2.0 的7项技术及讨论 压缩 SPDY、Friendly多路复用 SPDYTLS义务化 Speed + Mobility协商 Speed + Mobility、 Friendly客户端拉拽和服务器推送 Speed + Mobility流量控制 SPDYWebSocket Speed + Mobility Web服务器管理文件的WebDAVWebDAV(Web-based Distributed Authoring and Versioning,基于万维网的分布式创作和版本控制)是一个可对Web服务器上的内容直接进行文件复制、编辑等操作的分布式文件系统。除了创建、删除文件等基本功能,它还具备文件创建者管理、文件编辑过程中禁止其他用户内容覆盖的加锁功能,以及对文件内容修改的版本控制功能。使用HTTP/1.1的PUT方法和DELETE方法就可以对Web服务器上的文件进行创建和删除操作。但是出于安全性考虑一般是不使用的。 WebDAV新增的方法及状态码方法 FROPFIND:获取属性PROPPATCHL:修改属性MKCOL:创建集合…状体码 102 Processing:可正常处理请求,但目前是处理中状态207 Multi-Status:存在多种状态423 Locked:资源已被加锁…","link":"/2018/04/10/http协议分析/"}],"tags":[{"name":"短篇小说","slug":"短篇小说","link":"/tags/短篇小说/"},{"name":"莫泊桑","slug":"莫泊桑","link":"/tags/莫泊桑/"},{"name":"css","slug":"css","link":"/tags/css/"},{"name":"float","slug":"float","link":"/tags/float/"},{"name":"clear","slug":"clear","link":"/tags/clear/"},{"name":"BFC","slug":"BFC","link":"/tags/BFC/"},{"name":"毕业旅行","slug":"毕业旅行","link":"/tags/毕业旅行/"},{"name":"记忆","slug":"记忆","link":"/tags/记忆/"},{"name":"猫","slug":"猫","link":"/tags/猫/"},{"name":"长篇小说","slug":"长篇小说","link":"/tags/长篇小说/"},{"name":"村上春树","slug":"村上春树","link":"/tags/村上春树/"},{"name":"挪威的森林","slug":"挪威的森林","link":"/tags/挪威的森林/"},{"name":"http","slug":"http","link":"/tags/http/"},{"name":"https","slug":"https","link":"/tags/https/"},{"name":"websocket","slug":"websocket","link":"/tags/websocket/"},{"name":"cookie","slug":"cookie","link":"/tags/cookie/"},{"name":"缓存","slug":"缓存","link":"/tags/缓存/"},{"name":"代理","slug":"代理","link":"/tags/代理/"},{"name":"协议","slug":"协议","link":"/tags/协议/"},{"name":"加密","slug":"加密","link":"/tags/加密/"}],"categories":[{"name":"文学","slug":"文学","link":"/categories/文学/"},{"name":"前端","slug":"前端","link":"/categories/前端/"},{"name":"旅行","slug":"旅行","link":"/categories/旅行/"},{"name":"随笔","slug":"随笔","link":"/categories/随笔/"}]}