HTTP header

HTTP报文 一章中,我们介绍了HTTP协议由 行、头、体组成。而本章,介绍 “头”

如果你写了一个小爬虫,但抓出来的结果和想象的不同(例如界面样式,返回内容和人工看有差异,或者是需要登录),你可以更改你发送的HTTP请求的header部分,将合法的User-Agent、Cookie等添上,能解决大多数此类问题,因为HTTP是无状态并且不安全的协议,所以这些小手段能够生效。

下面取几个常用的头字段来做介绍。

请求首部:

请求首部就是由客户端,放在HTTP请求头中发送给服务器的部分。

User Agent(用户代理)

简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。从而为来自不同平台/浏览器的用户,提供最适合的响应内容。(例如,移动用户不应该收到PC网页的响应,就是由User Agent来做识别的)

Referer (来源)

它表示用户是从哪个网页发起的请求。通常用来做图片防盗链。
例如在图片服务器中解析请求判断Referer,如果非白名单站点发过来的请求,则返回一个防盗链的图片给请求方。

Mysql 事务隔离级别

当多个线程都开启事务操作数据库中的数据时,数据库系统要能进行隔离操作,以保证各个线程获取数据的准确性。


隔离级别

在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,在事务内和事务间的可见性。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。

READ UNCOMMITTED (未提交读/脏读)

在READ UNCOMMITTED级别中,事务所做的写操作,即使没有提交,对其他事务也是可见的,A事务可以读取B事务未提交的数据,这就叫做未提交读/脏读。 这个级别会导致很多问题,但从性能上来说,并不比其他级别好太多

READ COMMITTED (提交读/不可重复读)

大部分数据库系统的默认隔离级别就是 READ COMMITTED,它解决了脏读的问题,当一个事务开始时,只能“看见”已提交的事务所做的修改。但这也会引入一个不可重复读的问题:事务A在执行过程中有两次对变量a的读取,而在这两次读取之间,事务B对a做了修改,就会导致事务A的两次读取出的值不同,这就叫“不可重复读”。

HTTP 状态码

HTTP的状态码被分为了5大类,分别是:

1xx : Hold on (等着)
2xx : Here you go (执行完了,没毛病,拿着结果回去吧)
3xx : Go away (你要的不在我这儿,去别处找)
4xx : You fucked up (你丫出问题了)
5xx : I fucked up (我特么出问题了)

状态码为客户端提供了一种理解事务处理结果的便捷方式(比解析字符串方便多了)

1xx (信息性状态码):

一般来说,1xx类的状态码,发生在客户端和服务器交互过程中,两者对于某些情况做一定的约定,例如:

100 - Continue:说明收到了请求的初始部分,请客户端继续,发送了这个状态码之后,服务端在收到请求之后必须进行响应。

101 - Switching Protocols:说明服务器正在根据客户端的指定,将将协议切换成Update首部所列的协议

信息性状态码一般是在请求过程中,双方互相通知状态所使用,一般不会影响到本次请求的成功/失败。

HTTP 报文

报文的组成部分

HTTP报文 由起始行、首部、主体组成。

1、 起始行:

起始行是一个由行分隔的ASCII文本,每行都以一个由两个字符组成的行终止符作为结束,行终止符为 一个回车符 + 一个换行符,可以写作CRLF

2、 首部:

首部的格式与起始行相同

3、主体:

主体是一个可选的数据块,与起始行和首部不同的是,主题可以包含文本或二进制数据,也可以为空


报文的语法

所有的HTTP报文都可以分为两类:

1、请求报文:由客户端向web服务器请求一个动作

2、响应报文:向客户端返回请求的结果

例如,我们访问网址:http://jiayu.lu ,使用chrome浏览器,在地址栏中输入该网址并回车。此时按F12抓包的话,可以看见报文如下:

redis 事务

redis的事务和传统的关系型数据库不同,在关系型数据库中,用户首先向数据库发送一个BEGIN信号,然后执行各个相互一致的读写操作,最后,用户发送COMMIT来确认之前的操作,或者发送ROLLBACK来放弃之前的操作。

在redis中也有简单的方法可以处理一连串的读写操作,使用特殊命令MULTI为开始,然后传入一连串用户的操作,最后以EXEC结束,

但这种做法,实际上是在用户执行EXEC之前,客户端缓存保留所有命令,在EXEC之后一次性把所有命令发送到服务器执行,然后等待直到接收所有的命令回复为止,所以用户没办法根据读取到的数据来做决定是否rollback和commit。

但也正是因为它一次性传输所有命令的方式,可以将N条命令造成的N次网络往返,浓缩到1次网络往返,所以性能得到了提高

但是,考虑这样一个情况:我们的商品a在redis里只剩2件,此时有两个客户都在购买它,分别是客户端A和客户端B,此时它们俩都执行命令:

> GET a
2
> MULTI
ok
> ..... do something
> SET a 1
ok
> EXEC
ok

如果此时两个客户端在同时购买了此商品,那么可能会导致此时a被更新为1,而不是0,而这明显是错误的。

如何解决这个问题?