HTTP头

HTTP头

HTTP头

HTTP报文分为请求报文和响应报文。请求报文和响应报文的的第一行叫做状态行。状态行后面就跟着多个HTTP首部字段。
首先,咱们得清楚HTTP头部有什么作用,HTTP首部用来向请求报文或者响应报文中添加一些附加信息。通过HTTP首部信息,客户端或者服务器端就能了解到这次报文到底具有哪些属性,报文发送端有哪些喜好等等。
HTTP首部的分类:
1.通用首部:请求报文和响应报文都支持,换句话说,就是既可以出现在请求报文中,也可以出现在响应报文中。
2.请求首部:出现在请求报文第一行(请求行)的后面,为请求报文添加一些附加信息
3.响应首部:出现在响应报文第一行的后面,提供了一些关于响应报文的一些信息
4.实体首部:我们都知道,请求报文和响应报文都包含实体报文,实体首部就是用来描述实体报文的一些属性。
5.扩展头部:HTTP规范中没有定义的首部。

Header部分解释
1
2
3
4
5
6
7
8
9
10
11
12
13
Accept 	             指定客户端能够接收的内容类型 
Accept-Charset 浏览器可以接受的字符编码集
Accept-Encoding 指定浏览器可以支持的web服务器返回内容压缩编码类型。
Accept-Language 浏览器可接受的语言
Authorization HTTP授权的授权证书
Cache-Control 指定请求和响应遵循的缓存机制
Connection 表示是否需要持久连接。(HTTP 1.1默认进行持久连接)
Cookie HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。
Content-Length 请求的内容长度
Content-Type 请求的与实体内容类型
Date 请求发送的日期和时间
Referer 请求的来源url
User-Agent User-Agent的内容包含发出请求的用户信息

Header常见字段的举例

  • Accept:/

    最常见,指接受所有类型 还有text/plain,text/html,分别指接受纯文本和html格式

  • Accept-Encoding: gzip

    gzip是一种压缩方式,使用最为广泛,使用gzip可以省下很多网页流量,在网速一定的情况下,可以提高访问效率, 而deflate同样也为一种压缩方法(使用LZ77 算法和哈夫曼编码),使数据无损

  • Accept-Language: zh-CN;en-US

    语言,zh-CN是简体中文,而zh是中文,en-US是英文
    而q是权重系数,范围 0 =< q <= 1,q 值越大,请求越倾向于获得其“;”之前的类型表示的内容,若没有指定 q 值,则默认为1,若被赋值为0,则用于提醒服务器哪些是浏览器不接受的内容类型。

  • Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7

    浏览器支持的字符编码分别是 GB2312、utf-8 和任意字符,优先顺序是 GB2312、utf-8、
    其中
    表示任意字符编码,虽然 q 都是等于 0.7,但明确指定的 GB2312,utf-8 比 * 具有更高的优先级。

  • Connection: keep-alive

    HTTP请求是基于TCP连接的,TCP的请求会包含(三次握手,中间请求,四次挥手)
    在HTTP/1.0时代,一个HTTP请求就要三次握手和四次挥手,当一个网页中包含大量的图片或者其它外部资源时,加载一个Document要很多个HTTP请求,也就意味着要多次三次握手和四次挥手,这样就造成了网络资源的浪费
    到了HTTP/1.1的时候,通过请求头的connection字段用来申明,作用就是减少TCP握手次数,开始的三次握手后就可以进行多次HTTP正文请求,可以长时间的保持,也就是加载一个Document的时候,即使有大量的图片等,也只用进行一次握手,这样就大大的减少了传输量了。keep-alive就表示之前已经进行过握手,可以直接进行HTTP正文传输,close表示结束,我接下来没有东西了,可以进行四次挥手结束这个TCP连接了

  • Content-Type
    Http Header里的Content-Type一般有:
    1.application/x-www-form-urlencoded: 数据被编码为名称/值对。这是标准的编码格式。
    2.multipart/form-data: 传输文件。
    3.text/plain: 数据以纯文本形式进行编码
    4.application/json: json格式

对于一个form表单,其enctrype属性即为编码方式
常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application/x-www-form-urlencoded。

x-www-form-urlencoded

jquery的ajax方法默认使用application/x-www-form-urlencoded
当请求的Content-Type为application/x-www-form-urlencoded浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2…)
同理为application/json时会转换为json数据格式

form-data

http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。
既可以上传键值对,也可以上传文件。
当上传的字段是文件时,会有Content-Type来表名文件类型而content-disposition,用来说明字段的一些信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。

boundary通常由浏览器随机生成

示例

使用HTTP Client 对本地服务器模拟post操作
后端为Django

使用application/x-www-form-urlencoded

1
2
3
4
5
6
POST http://127.0.0.1:8000/test.api/
Accept: */*
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded

name=test&list=aaaa&list=456
后端捕获代码
1
2
form_name = request.POST.get("name", None)
form_list = request.POST.getlist("list", None)

list被解析为列表而name被解析为k-v对,我们看到,虽然x-www-form-urlencoded是以k-v对的形式来传递参数的,这并不意味着它不能传递数组(列表),我们只需指定传递的key相同值不同的多组数据即可

使用multipart/form-data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
POST http://127.0.0.1:8000/test.api/
Accept: */*
Cache-Control: no-cache
Content-Type: multipart/form-data;boundary=yurnnlukjwfbrdiqvnqnegfitaaddkom

--yurnnlukjwfbrdiqvnqnegfitaaddkom
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: image/jpg

< E:\img\path\name.jpg

--yurnnlukjwfbrdiqvnqnegfitaaddkom
Content-Disposition: form-data;name="list";
Content-Type: text/plain

11

--yurnnlukjwfbrdiqvnqnegfitaaddkom
Content-Disposition: form-data;name="list";
Content-Type: text/plain

background

--yurnnlukjwfbrdiqvnqnegfitaaddkom
Content-Disposition: form-data;name="name";
Content-Type: text/plain

cyx
--yurnnlukjwfbrdiqvnqnegfitaaddkom--
后端捕获代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
form_file = request.FILES.get("pic", None)
form_name = request.POST.get("name", None)
form_list = request.POST.getlist("list", None)
if form_file is not None:
random_name = str(uuid.uuid1())
"".join(random_name.split("-"))
path = path + "\\" + random_name + ".jpg"
with open(path, "wb") as destination:
for chunk in form_file:
destination.write(chunk)
destination.close()
print("write a pic")
if form_name is not None:
print(form_name)
if form_list is not None:
for i in form_list:
print(i)
return render(request, 'test.html')

# 结果
# write a pic
# cyx
# 11
# background

我们指定boundary的值为
yurnnlukjwfbrdiqvnqnegfitaaddkom,这个完全根据自定义,但一般浏览器会以若干—-开头以防止和数据名称或内容等冲突导致出错
我们的图片是以2进制的形式上传的,所以写入操作也要对应为2进制文件操作

Response常见字段举例

  • Cache-Control(默认为private)
    常用属性值。
    1.no-cache:这个属性呢,不要被他的样貌给迷惑了,它并不是不缓存响应报文,只不过在服务器返回响应时,缓存都要向服务器评估缓存的新鲜度。也就是说,如果服务器返回的响应相比缓存有所变动,则使用服务器的响应。
    2.no-store:该指令规定不缓存任何内容(注意和no-cache的区别)
    3.max-age:用法max-age=60(秒),用来表示缓存资源的保鲜时间。当缓存的内容缓存时间大于该值时,请求将重新转发至服务器。
    4.s-maxage:用法和max-age相同,并且行为和max-age也相同,不同的是s-maxage适用于公共缓存。
    通过指定“Expires”(过期时间)值也会影响到缓存。与max-age不同的是,expires的值是绝对时间,而max-age是相对时间(我的理解)

CORS

CORS(cross-origin sharing standard)

什么情况下需要CORS?

  • XMLHttpRequest或Fetch
  • Web字体
    等等

    使用XMLHttpRequest (XHR)对象可以与服务器交互。您可以从URL获取数据,而无需让整个的页面刷新。这使得Web页面可以只更新页面的局部,而不影响用户的操作。XMLHttpRequest在 Ajax 编程中被大量使用。

什么时候触发

CORS可以让你实现跨站点请求并同时阻止恶意js的请求,它会在你发送下面几种HTTP请求时触发:

  • 不同的域名 (比如在网站 example.com 请求 api.com)
  • 不同的子域名 (比如在网站 example.com 请求 api.example.com)
  • 不同的端口 (比如在网站 example.com 请求 example.com:3001)
  • 不同协议 (比如在网站 https://example.com 请求 http://example.com)

跨域请求

只有服务器实现了cors接口才可以进行跨域请求
cors对于浏览器发过来的ajax请求有简单请求和非简单请求

  • 简单请求:
    HEAD, GET, POST请求
    浏览器会在header中加上字段 key:origin value:协议+域名+端口(如http://localhost:8080)
    服务器根据origin值来决定是否同意这个请求
    如果请求通过会在header中多增加几个字段:
    Access-Control-Allow-Origin: http://localhost:8080 (仍以上为例)
    用来明确指定那些客户端的域名允许访问这个资源。它的值可以是:
    允许任意域名(*)或者和一个完整的域名名字(比如:https://example.com)
    Access-Control-Allow-Credentail:True(是否包含cookie)
  • 非简单请求
    非简单请求需要发一个option方法的预检请求,成功后浏览器开始发出cors请求,其余与前面相同
    其余的我暂时没有过多了解

Referer

Referer是HTTP请求header 的一部分,当浏览器(或者模拟浏览器行为)向web服务器发送请求的时候,头信息里有包含Referer

比如我在www.google.com里有一个www.baidu.com链接那么点击这个www.baidu.com,它的header信息里就有Referer=http://www.google.com

Referer的正确英语拼法是referrer。由于早期HTTP规范的拼写错误,为了保持向后兼容就将错就错了。其它网络技术的规范企图修正此问题,使用正确拼法,所以目前拼法不统一。还有它第一个字母是大写。

X-Forward-For

X-Forward-For跟Referer和User-Agent一样,都是 HTTP 中的头域。
当存在X-Forward-For字段时,说明原始请求使用了代理,
X-Forward-For的正向用途是便于服务端识别原始IP。

假设有一个ip为192.0.2.40的客户端,它经过多个代理访问服务器:
代理服务器1:ip=192.0.2.22
代理服务器2:ip=192.0.2.33
服务器:ip=192.0.2.44

那么各个服务器之间的X-Forward-For字段分别为:

  • 代理服务器1和客户端:
    请求中没有 Forwarded 头域
  • 代理服务器2和代理服务器1:Forwarded:for=192.0.2.40
  • 代理服务器2和服务器:
    Forwarded:for=192.0.2.40, for:192.0.2.22;by:192.0.2.44;proto=http;host=example.com
    由于客户端到代理1的请求没有使用代理,所以值为空或短横线。到代理2时,中间经过了代理1,所以值为原始IP。到服务端时,中间经过了代理1和代理2,所以值为原始IP和代理 1IP

当然,这个字段可以伪造,这样服务器就无法知道你的真实IP

写在后面

对于之前的一次内容的整理和翻新,后续会继续添加,可能会有格式的小问题,后续会进行修改

Author

Ctwo

Posted on

2019-12-03

Updated on

2020-10-25

Licensed under

Comments