当前位置 : 首页 » 文章分类 :  开发  »  HTTP

HTTP

HTTP 协议相关笔记
HTTP - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP
MDN 的 HTTP 文档全面且详细,质量很高,还有中文翻译,是学习 HTTP 标准非常好的工具。


IANA端口号分配查询

Service Name and Transport Protocol Port Number Registry
https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml


httpbin

不太稳定,经常 502

常用接口地址:
get请求网址:https://httpbin.org/get
post请求网址:https://httpbin.org/post
put请求网址:https://httpbin.org/put
patch请求网址:https://httpbin.org/patch
delete请求网址:https://httpbin.org/delete
返回headers信息:https://httpbin.org/headers
返回你使用的访问此链接的IP地址:https://httpbin.org/ip
返回USER-AGENT信息:https://httpbin.org/user-agent


RFC2616(HTTP1.1)

IETF Datatracker 用来搜索 RFC 文档很方便
https://datatracker.ietf.org/

纯文本的 RFC2616 规定了 HTTP/1.1 协议,有时间可以详细阅读下。
https://www.ietf.org/rfc/rfc2616.txt

Datatracker 版本的 RFC2616 能看到版本历史
https://datatracker.ietf.org/doc/rfc2616/

DevResCollect/HTTP协议(RFC2616)中文版.pdf
https://github.com/dreamofxw/DevResCollect/blob/master/HTTP%E5%8D%8F%E8%AE%AE(RFC2616)%E4%B8%AD%E6%96%87%E7%89%88.pdf


GET 请求能否带body

RFC 7230~7235 指出 GET 请求中的 body 无语义

GET 请求消息中的有效负载(即 body)没有定义的语义;
在 GET 请求上发送有效负载主体可能会导致某些现有实现拒绝该请求。

浏览器不支持 GET 请求带 body

浏览器中使用 Ajax 发送带 body 的 GET 请求,body 会被忽略

多数三方库/语言都支持 GET 请求带 body

例如
Python 的 requests 库
java、node 等的 http 库
nginx、curl 命令
都支持 GET 请求带 body

更甚者,Elasticsearch 的好多官方 HTTP API 都使用 GET 带 body

HTTP GET 请求可以有 body 吗?
https://zhuanlan.zhihu.com/p/456921996


HTTP 状态码

1xx,信息,服务器收到请求,需要请求者继续执行操作
2xx,成功,操作被成功接收并处理
3xx,重定向,需要进一步的操作以完成请求
4xx,客户端错误,请求包含语法错误或无法完成请求
5xx,服务器错误,服务器在处理请求的过程中发生了错误

200 OK 请求被成功处理,服务器会根据不同的请求方法返回结果:
GET:请求的对应资源会作为响应返回。
HEAD:请求的对应资源的响应头(entity-header)会作为响应返回,不包括响应体(message-body)。
POST:返回处理对应请求的结果。

403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
500 Internal Server Error 服务器内部错误,无法完成请求
502 Bad Gateway 出现502的原因是:对用户访问请求的响应超时造成的。连接超时 我们向服务器发送请求 由于服务器当前链接太多,导致服务器方面无法给于正常的响应,产生此类报错

HTTP 状态码详解与选用
https://mp.weixin.qq.com/s?__biz=MzA4MjkxMzMyNg==&mid=2654068952&idx=1&sn=1bd63a71610d73fcd563888d6f93398d&scene=24&srcid=0804843QrwLCsKWGYxfPum2H#wechat_redirect


301 Moved Permanently

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/301

HTTP 301 永久重定向 说明请求的资源已经被移动到了由 Location 头部指定的url上,是固定的不会再改变。搜索引擎会根据该响应修正。

302 Found

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/302
HTTP 302 Found 重定向状态码表明请求的资源被暂时的移动到了由Location 头部指定的 URL 上。浏览器会重定向到这个URL, 但是搜索引擎不会对该资源的链接进行更新 (In SEO-speak, it is said that the link-juice is not sent to the new URL)。

301 Moved Permanently 与 302 Found 的区别

301 Moved Permanently
302 Found

301, 302 都是 HTTP 状态的编码,都代表着某个 URL 发生了转移,不同之处在于:
301 redirect: 301 代表永久性转移(Permanently Moved)。
302 redirect: 302 代表暂时性转移(Temporarily Moved )。

1、对用户来说
301, 302 对用户来说没有区别,他们看到效果只是一个跳转,浏览器中旧的 URL 变成了新的 URL. 页面跳到了这个新的 url 指向的地方。
2、对搜索引擎来说
301 重定向是永久的重定向,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址。
302 重定向是临时的重定向,搜索引擎会抓取新的内容而保留旧的网址。因为服务器返回 302 代码,搜索引擎认为新的网址只是暂时的。

302 转向可能会有 URL 规范化及网址劫持的问题。可能被搜索引擎判为可疑转向,甚至认为是作弊。

当网页 A 用 301 重定向转到网页 B 时,搜索引擎可以肯定网页 A 永久的改变位置,或者说实际上不存在了,搜索引擎就会把网页 B 当作唯一有效目标。
301 的好处是:
第一,没有网址规范化问题。
第二,也很重要的,网页 A 的 PR 网页级别会传到网页 B。
所以,尽量要使用 301 跳转

HTTP返回码中301与302的区别
https://blog.csdn.net/qmhball/article/details/7838989


401 Unauthorized 未认证

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/401

状态码 401 Unauthorized 代表客户端错误,指的是由于缺乏目标资源要求的身份验证凭证,发送的请求未得到满足。

这个状态码会与 WWW-Authenticate 首部一起发送,其中包含有如何进行验证的信息。

这个状态类似于 403, 但是在该情况下,依然可以进行身份验证。

403 Forbidden 未授权

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/403

状态码 403 Forbidden 代表客户端错误,指的是服务器端有能力处理该请求,但是拒绝授权访问。

这个状态类似于 401,但进入该状态后不能再继续进行验证。该访问是长期禁止的,并且与应用逻辑密切相关(例如不正确的密码)。

401 Unauthorized 和 403 Forbidden 的区别

401 Unauthorized
403 Forbidden

401 和 403 的区别就是 认证(authentication) 和 授权(authorization) 的区别

认证(authentication) 是为了验证“你是不是你”,一般通过账号密码验证用户的身份。
授权(authorization) 授权发生在认证之后,继续检查用户是否有访问某个资源的权限。

401 是没有带认证信息或者带了错误的认证信息, 这时客户端可以修改认证信息进行重试;
403 是客户端带了正确的认证信息, 但服务器认为这个认证信息对应的用户是没有对应资源的访问权限的, 因此, 在向管理员获取相关权限之前, 是没有重试的必要的.

401 Unauthorized 该 HTTP 状态码表示认证错误,它是为了认证设计的,而不是为了授权设计的。收到 401 响应,表示请求没有被认证—压根没有认证或者认证不正确—但是请重新认证和重试。(一般在响应头部包含一个 WWW-Authenticate 来描述如何认证)。通常由 web 服务器返回,而不是 web 应用。从性质上来说是临时的东西。(服务器要求客户端重试)

403 Forbidden 该 HTTP 状态码是关于授权方面的。从性质上来说是永久的东西,和应用的业务逻辑相关联。它比 401 更具体,更实际。收到 403 响应表示服务器完成认证过程,但是客户端请求没有权限去访问要求的资源。


413 Payload Too Large

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/413

响应状态码 413 Payload Too Large 表示请求主体的大小超过了服务器愿意或有能力处理的限度,服务器可能会(may)关闭连接以防止客户端继续发送该请求。

nginx 中
client_max_body_size 指令设置 NGINX 能处理的最大 request body 大小。
如果请求大于指定的大小,则 NGINX 发回 413 (Request Entity Too Large) 错误。
如果服务器处理大文件上传,则该指令非常重要。
默认情况下,该指令值为1m。


502 Bad Gateway 后端服务挂了

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/502

502 Bad Gateway。一般表现为你自己写的「应用层服务(Java/Go/PHP)挂了」,或者网关指定的上游服务直接指错了地址,网关层无法接收到响应

503 Service Unavailable 后端服务过载

由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理500响应的方式处理它。  
注意:503状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接。

504 Gateway Timeout 后端服务超时

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status/504

504 Gateway Timeout。一般表现为「应用层服务 (Upstream) 超时,超过了 Gatway 配置的 Timeout」,如查库操作耗时三分钟,超过了 Nginx 配置的超时时间
作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。


一张图说明HTTP决策过程与状态码


HTTP 决策过程与状态码

URL原理、URL编码、URL特殊字符

JavaScript中提供了3对函数用来对Url编码以得到合法的Url,它们分别是escape / unescape, encodeURI / decodeURI和encodeURIComponent / decodeURIComponent。由于解码和编码的过程是可逆的,因此这里只解释编码的过程。

下面列出了这三个函数的安全字符(即函数不会对这些字符进行编码)

  • escape(69个):*/@+-._0-9a-zA-Z
  • encodeURI(82个):!#$&'()*+,/:;=?@-._~0-9a-zA-Z
  • encodeURIComponent(71个):!'()*-._~0-9a-zA-Z

encodeURI() 是 Javascript 中真正用来对 URL 编码的函数。它着眼于对整个URL进行编码。

URL原理、URL编码、URL特殊字符
https://blog.csdn.net/freeking101/article/details/68922983


Headers

HTTP Headers - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

HTTP 消息头允许客户端和服务器通过 request 和 response 传递附加信息。一个请求头由名称(不区分大小写)后跟一个冒号”:”,冒号后跟具体的值(不带换行符)组成。该值前面的引导空白会被忽略。

自定专用消息头可通过 X- 前缀来添加;但是这种用法被IETF在2012年6月发布的 RFC5548 中明确弃用,原因是其会在非标准字段成为标准时造成不便;其他的消息头在 IANA 注册表 中列出, 其原始内容在 RFC 4229 中定义。 此外,IANA 还维护着 被提议的新 HTTP 消息头注册表.

Connection

Connection 头(header) 决定当前的事务完成后,是否会关闭网络连接。如果该值是 keep-alive,网络连接就是持久的,不会关闭,使得对同一个服务器的请求可以继续在该连接上完成。

Connection: keep-alive
Connection: close

使用 HTTP/1.0 的客户端在首部中加上”Connection:Keep-Alive”,请求服务端将一条连接保持在打开状态。服务端如果愿意将这条连接保持在打开状态,就会在响应中包含同样的首部。如果响应中没有包含”Connection:Keep-Alive”首部,则客户端会认为服务端不支持keep-alive,会在发送完响应报文之后关闭掉当前连接。

HTTP/1.1 的连接默认情况下都是持久连接。如果要显式关闭,需要在报文中加上 Connection:Close 首部。即在 HTTP/1.1 中,所有的连接都进行了复用。

Keep-Alive

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive

Connection: Keep-Alive
Keep-Alive: timeout=5, max=1000

timeout 过期时间5秒
max 最多 1000 次请求,强制断掉连接。在timeout时间内又有新的连接过来,同时max会自动减1,直到为0,强制断掉。

Upgrade

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Upgrade

X-Forwarded-For

X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC7239 (Forwarded HTTP Extension) https://tools.ietf.org/html/rfc7239 标准之中。

一般来说,X-Forwarded-For是用于记录代理信息的,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加在X-Forwarded-For中

X-Forwarded-For 请求头格式非常简单,就这样:

X-Forwarded-For: client, proxy1, proxy2, ...

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

如果一个 HTTP 请求到达服务器之前,经过了三个代理 Proxy1、Proxy2、Proxy3,IP 分别为 IP1、IP2、IP3,用户真实 IP 为 IP0,那么按照 XFF 标准,服务端最终会收到以下信息:

X-Forwarded-For: IP0, IP1, IP2

Proxy3 直连服务器,它会给 XFF 追加 IP2,表示它是在帮 Proxy2 转发请求。列表中并没有 IP3,IP3 可以在服务端通过 Remote Address 字段获得。我们知道 HTTP 连接基于 TCP 连接,HTTP 协议中没有 IP 的概念,Remote Address 来自 TCP 连接,表示与服务端建立 TCP 连接的设备 IP,在这个例子里就是 IP3。

Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。不同语言获取 Remote Address 的方式不一样,例如 php 是 $_SERVER["REMOTE_ADDR"],Node.js 是 req.connection.remoteAddress,但原理都一样。

HTTP 请求头中的 X-Forwarded-For
https://imququ.com/post/x-forwarded-for-header-in-http.html


X-Real-IP

X-Real-IP 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。
需要注意的是,X-Real-IP 目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息。

remote_addr

X-Forwarded-For和X-Real-IP只有请求存在代理时才有值,而remote_addr一直存在。

  • X-Forwarded-For:记录代理服务器的地址,每经过一个代理,该字段会追加上一个记录。格式形如:1.1.1.1, 2.2.2.2。
  • X-Real-IP:也是用来记录服务器的地址,但是和上面的不同,它不把记录添加到结尾,而是直接替换。
  • remote_addr:上一个客户端连接的地址,不存在代理就表示客户端的地址,存在代理就表示最后一个代理服务器的地址。

[COLLECT]HTTP头中X-FORWARDED-FOR、X-REAL-IP、REMOTE_ADDR这几者之间的区别
https://ixyzero.com/blog/archives/4088.html


Accept

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept

Accept 请求头用来告知(服务器)客户端可以处理的内容类型。

Accept 标头列举了用户代理希望接收的媒体资源的 MIME 类型。其中不同的 MIME 类型之间用逗号分隔,同时每一种 MIME 类型会配有一个品质因数(quality factor),该参数明确了不同 MIME 类型之间的相对优先级。

Accept 标头的值由浏览器或其他类型的用户代理确定,并且会由于上下文环境的不同而不同。比如在获取 HTML 页面、图片文件、视频文件或者是脚本文件的时候,无论是通过在地址栏中输入资源地址来获取还是通过 <img><video><audio> 元素引用都是不一样的。


Content-Type

Content-Type - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Type

Content-Type 实体头部用于指示资源的 MIME 类型 media type 。

在响应中,Content-Type 标头告诉客户端实际返回的内容的内容类型。
浏览器会在某些情况下进行 MIME 查找,并不一定遵循此标题的值; 为了防止这种行为,可以将标题 X-Content-Type-Options 设置为 nosniff。

Content-Type 决定浏览器将以什么形式、什么编码读取这个文件。

X-Content-Type-Options 禁止MIME嗅探

X-Content-Type-Options - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Content-Type-Options

X-Content-Type-Options HTTP 消息头相当于一个提示标志,被服务器用来提示客户端一定要遵循在 Content-Type 首部中对 MIME 类型 的设定,而不能对其进行修改。这就禁用了客户端的 MIME 类型嗅探行为,换句话说,也就是意味着网站管理员确定自己的设置没有问题。

该消息头最初是由微软在 IE 8 浏览器中引入的,提供给网站管理员用作禁用内容嗅探的手段,内容嗅探技术可能会把不可执行的 MIME 类型转变为可执行的 MIME 类型。在此之后,其他浏览器也相继引入了这个消息头,尽管它们的 MIME 嗅探算法没有那么有侵略性。

语法
X-Content-Type-Options: nosniff


Content-Disposition

Content-Disposition - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Disposition

在常规的 HTTP 应答中,Content-Disposition 响应头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。

在 multipart/form-data 类型的应答消息体中, Content-Disposition 消息头可以被用在 multipart 消息体的子部分中,用来给出其对应字段的相关信息。各个子部分由在 Content-Type 中定义的分隔符分隔。用在消息体自身则无实际意义。

RFC 6266

RFC 6266 介绍了 Content-Disposition 响应头
Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)
https://datatracker.ietf.org/doc/html/rfc6266

语法:

content-disposition = "Content-Disposition" ":"
                            disposition-type *( ";" disposition-parm )

     disposition-type    = "inline" | "attachment" | disp-ext-type
                         ; case-insensitive
     disp-ext-type       = token

     disposition-parm    = filename-parm | disp-ext-parm

     filename-parm       = "filename" "=" value
                         | "filename*" "=" ext-value

     disp-ext-parm       = token "=" value
                         | ext-token "=" ext-value
     ext-token           = <the characters in token, followed by "*">

disposition-type 有两种:

  • inline 代表默认处理,一般会在页面展示
  • attachment 代表应该被保存到本地,需要配合设置 filename 或 filename*

filename-parm 中的 filename 和 filename* 指定保存的文件名:

  • filename 的 value 不进行编码
  • filename* 遵从 RFC 5987 中定义的编码规则
    Producers MUST use either the “UTF-8” ([RFC3629]) or the “ISO-8859-1” ([ISO-8859-1]) character set. Extension character sets (mime- charset) are reserved for future use.

filename* 是后续定义的,有些老浏览器可能不支持。filename 和 filename* 同时出现时,采用filename*,忽略filename

下载的附件名总乱码?你该去读一下 RFC 文档了!
https://segmentfault.com/a/1190000023601065


普通 HTTP 消息中的 Content-Disposition

在 HTTP 场景中,第一个参数或者是 inline(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),或者是 attachment(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,将 filename 的值预填为下载后的文件名,假如它存在的话)。

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"

比如,以下是一则可以触发”保存为”对话框的服务器应答:

200 OK
Content-Type: text/html; charset=utf-8
Content-Disposition: attachment; filename="cool.html"
Content-Length: 22

<HTML>Save me!</HTML>

multipart 消息中的 Content-Disposition

当使用 multipart/form-data 格式提交表单数据时,每个子部分(例如每个表单字段和任何与字段数据相关的文件)都需要提供一个 Content-Disposition 标头,以提供相关信息。标头的第一个指令始终为 form-data,并且还必须包含一个 name 参数来标识相关字段。额外的指令不区分大小写,并使用带引号的字符串语法在 = 号后面指定参数。多个参数之间使用分号(;)分隔。

Content-Disposition: form-data
Content-Disposition: form-data; name="fieldName"
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"

浏览器打开图片 URL 是显示还是下载

1、Content-Disposition 响应头决定浏览器是展示还是下载内容,Content-Disposition 设置为 attachment 会强制下载。
2、Content-Type 设置为 application/octet-stream 也会导致强制下载,这个是二进制的下载流。


Transfer-Encoding

语法

Transfer-Encoding: chunked
Transfer-Encoding: compress
Transfer-Encoding: deflate
Transfer-Encoding: gzip
Transfer-Encoding: identity

Chunked

分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种数据传输机制,允许 HTTP 由网页伺服器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。

分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供,HTTP/2 不支持 HTTP/1.1 的分块传输编码

通常,HTTP 应答消息中发送的数据是整个发送的,Content-Length 消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。

HTTP 分块传输编码允许服务器为动态生成的内容维持HTTP持久链接。通常,持久链接需要服务器在开始发送消息体前发送 Content-Length 消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。

分块传输编码是一种在 HTTP 响应中动态生成数据并将其以多个块(chunks)发送给客户端的机制。这种编码方式允许服务器在生成响应时逐步发送数据,而不需要事先确定整个响应的长度。
分块传输编码的工作原理如下:
1、服务器将响应分割为一系列固定大小的数据块。
2、每个数据块包含一个头部和块数据。头部中包含当前数据块的大小信息。
3、服务器发送每个数据块,并在最后发送一个空(大小为0)的数据块作为结束标志,表示响应的完整性。
这种分块传输的方式对于动态生成大型响应或响应时间较长的情况很有用,它可以使客户端能够更早地开始处理响应数据,而无需等待整个响应完成。


Pragma

Pragma: no-cache

no-cache
Cache-Control: no-cache 效果一致。强制要求缓存服务器在返回缓存的版本之前将请求提交到源头服务器进行验证。

由于 Pragma 在 HTTP 响应中的行为没有确切规范,所以不能可靠替代 HTTP/1.1 中通用首部 Cache-Control,尽管在请求中,假如 Cache-Control 不存在的话,它的行为与 Cache-Control: no-cache 一致。建议只在需要兼容 HTTP/1.0 客户端的场合下应用 Pragma 首部。


MIME 类型/Content-Type

MIME 类型 - MDN
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types

媒体类型(通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型 )是一种标准,用来表示文档、文件或字节流的性质和格式。它在 IETF RFC 6838 中进行了定义和标准化。

在 Http 协议消息头中,使用 Content-Type 头部来表示具体请求中的媒体类型信息。

IANA 的 Media Types 列表页面

互联网号码分配机构(IANA)是负责跟踪所有官方MIME类型的官方机构,您可以在媒体类型 Media Types 页面中找到最新的完整列表。

MIME 结构

type/subtype
MIME的组成结构非常简单;由类型与子类型两个字符串中间用’/‘分隔而组成。不允许空格存在。type 表示可以被分多个子类的独立类别。subtype 表示细分后的每个类型。

MIME类型对大小写不敏感,但是传统写法都是小写。

MIME 分类

类型 描述 典型示例
text 人类可读的普通文本 text/plain, text/html, text/css, text/javascript
image 表明是某种图像。 image/gif, image/png, image/jpeg, image/bmp, image/webp, image/x-icon, image/vnd.microsoft.icon
audio 表明是某种音频文件 audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
video 表明是某种视频文件 video/webm, video/ogg
application 表明是某种二进制数据 application/octet-stream, application/pkcs12, application/vnd.mspowerpoint, application/xhtml+xml, application/xml, application/pdf

对于 text 文件类型若没有特定的 subtype,就使用 text/plain。
类似的,二进制文件没有特定或已知的 subtype,即使用 application/octet-stream。

text 类型

text/html : HTML格式
text/xml : XML格式
text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符

image 类型

image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式

application 类型

application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/json : JSON数据格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
对于前端使用而言,form表单的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application/x-www-form-urlencoded

application/octet-stream

这是应用程序文件的默认值。意思是 未知的应用程序文件 ,浏览器一般不会自动执行或询问执行。
览器会像对待 设置了 HTTP 头 Content-Disposition 值为 attachment 的文件一样来对待这类文件。

很多 web 服务器使用默认的 application/octet-stream 来发送未知类型。出于一些安全原因,对于这些资源浏览器不允许设置一些自定义默认操作,导致用户必须存储到本地以使用

Multipart 类型

Multipart 类型包括

multipart/form-data
multipart/byteranges

multipart/form-data

multipart/form-data 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。

在开发中很多时候需要会涉及到上传图片等服务器交互的操作 , 这基本上全部都会使用 multipart/form-data 的请求方式来完成上传。
multipart/form-data 定义在 rfc2388 中,最早的 HTTP POST 是不支持文件上传的,给编程开发带来很多问题。但是在1995年,ietf 出台了 rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。所以 Content-Type 的类型扩充了multipart/form-data 用以支持向服务器发送二进制数据。

因此,发送 POST 请求时候,表单 <form> 属性 enctype 共有二个值可选,这个属性管理的是表单的 MIME 编码:
application/x-www-form-urlencoded (默认值)
multipart/form-data
注:form 表单中 enctype 的默认值是 enctype=”application/x-www-form-urlencoded”

通过 form 表单提交文件操作如下:

<FORM method="POST" action="http://w.sohu.com/t2/upload.do" enctype="multipart/form-data">
    <INPUT type="text" name="city" value="Santa colo">
    <INPUT type="text" name="desc">
    <INPUT type="file" name="pic">
</FORM>

浏览器将会发送以下数据:

POST /t2/upload.do HTTP/1.1
User-Agent: SOHUWapRebot
Accept-Language: zh-cn,zh;q=0.5
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Content-Length: 60408
Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Host: w.sohu.com

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data; name="city"

Santa colo
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="desc"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

...
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

... binary data of the jpg ...
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

请求头部的信息 boundary 这个参数是分界线的意思 , 也就是说你在请求头中指定分界线为: ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC , 那么请求体中凡是遇到这个字符串都会被视为分界线 , 这个分界线参数具体是什么你可以随意自定义。

深入解析 multipart/form-data
https://www.jianshu.com/p/29e38bcc8a1d

Multipart/form-data
https://www.jianshu.com/p/e810d1799384


互联网服务离不开用户认证。一般流程是下面这样。
1、用户向服务器发送用户名和密码。
2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
3、服务器向用户返回一个 session_id,写入用户的 Cookie。
4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

session(服务端生成)

Session 是存放在服务器端的,类似于 Session 结构来存放用户数据,当浏览器 第一次发送请求时,服务器自动生成了一个 Session 和一个Session ID用来唯一标识这个Session,并将其通过响应发送到浏览器。当浏览器第二次发送请求,会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的Session。

一般情况下,服务器会在一定时间内(默认30分钟)保存这个 Session,过了时间限制,就会销毁这个Session。在销毁之前,程序员可以将用户的一些数据以Key和Value的形式暂时存放在这个 Session中。当然,也有使用数据库将这个Session序列化后保存起来的,这样的好处是没了时间的限制,坏处是随着时间的增加,这个数据 库会急速膨胀,特别是访问量增加的时候。一般还是采取前一种方式,以减轻服务器压力。

浅谈Session与Cookie的区别与联系
https://blog.csdn.net/duan1078774504/article/details/51912868

浏览器端session id的保存方法

一般浏览器提供了两种方式来保存,还有一种是程序员使用html隐藏域的方式自定义实现:
[1] 使用Cookie来保存,这是最常见的方法,本文“记住我的登录状态”功能的实现正式基于这种方式的。服务器通过设置Cookie的方式将Session ID发送到浏览器。如果我们不设置这个过期时间,那么这个Cookie将不存放在硬盘上,当浏览器关闭的时候,Cookie就消失了,这个Session ID就丢失了。如果我们设置这个时间为若干天之后,那么这个Cookie会保存在客户端硬盘中,即使浏览器关闭,这个值仍然存在,下次访问相应网站时,同 样会发送到服务器上。

[2] 使用URL附加信息的方式,也就是像我们经常看到JSP网站会有 aaa.jsp?JSESSIONID=xxx 一样的。这种方式和第一种方式里面不设置Cookie过期时间是一样的。当禁用cookie时,会使用这种方式保存session id

[3] 第三种方式是在页面表单里面增加隐藏域,这种方式实际上和第二种方式一样,只不过前者通过GET方式发送数据,后者使用POST方式发送数据。但是明显后者比较麻烦。

浅谈Session与Cookie的区别与联系
https://blog.csdn.net/duan1078774504/article/details/51912868

cookie和session的区别

1、session保存在服务器,客户端不知道其中的信息;cookie保存在客户端,服务器能够知道其中的信息。
2、session中保存的是对象,cookie中保存的是字符串。
3、session不能区分路径,同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到。而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的。
4、cookie目的可以跟踪会话,也可以保存用户喜好或者保存用户名密码。session用来跟踪会话
5、session是存储在服务端的,不能伪造。cookie是存储在浏览器端的,如果你能够截获某个用户的cookie变量,然后伪造一个数据包发送过去,那么服务器还是 认为你是合法的。所以,使用cookie被攻击的可能性比较大。
6、session过期与否,取决于服务器的设定。cookie过期与否,可以在cookie生成的时候设置进去。

1,session 在服务器端,cookie 在客户端(浏览器)
2,session 默认被存在在服务器的一个文件里(不是内存)
3,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id)
4,session 可以放在 文件、数据库、或内存中都可以。
5,用户验证这种场合一般会用 session
因此,维持一个会话的核心就是客户端的唯一标识,即 session id

为什么需要session?(http无状态,跟踪会话)

由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。

http是无状态的协议,客户每次读取web页面时,服务器都打开新的会话,而且服务器也不会自动维护客户的上下文信息,那么要怎么才能实现网上商店中的购物车呢,session就是一种保存上下文信息的机制,它是针对每一个用户的,变量的值保存在服务器端,通过SessionID来区分不同的客户,session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie,我们叫做session cookie,以区别persistent cookies,也就是我们通常所说的cookie,注意session cookie是存储于浏览器内存中的,并不是写到硬盘上的,这也就是我们刚才看到的JSESSIONID,我们通常情是看不到JSESSIONID的,但是当我们把浏览器的cookie禁止后,web服务器会采用URL重写的方式传递Sessionid,我们就可以在地址栏看到 sessionid=KWJHUG6JJM65HS2K6之类的字符串。

session cookie针对某一次会话而言,会话结束session cookie也就随着消失了,是存储在内存当中的。
而persistent cookie只是存在于客户端硬盘上的一段文本(通常是加密的),而且可能会遭到cookie欺骗以及针对cookie的跨站脚本攻击,自然不如 session cookie安全了。

如果cookie设置了有效值,那么cookie会保存到客户端的硬盘上,下次在访问网站的时候,浏览器先检查有没有cookie,如果有的话,读取cookie,然后发送给服务器。

伪造cookie

如果你能够截获某个用户的cookie变量,然后伪造一个数据包发送过去,那么服务器还是 认为你是合法的。所以,使用cookie被攻击的可能性比较大。

所以你在机器上面保存了某个论坛cookie,有效期是一年,如果有人入侵你的机器,将你的cookie拷走,放在他机器下面,那么他登陆该网站的时候就是用你的身份登陆的。当然,伪造的时候需要注意,直接copy cookie文件到 cookie目录,浏览器是不认的,他有一个index.dat文件,存储了 cookie文件的建立时间,以及是否有修改,所以你必须先要有该网站的 cookie文件,并且要从保证时间上骗过浏览器

Cookie和Session的区别
https://www.cnblogs.com/L-a-u-r-a/p/8595874.html

应用场景

1、日常登录一个网站,今天输入用户名密码登录了,第二天再打开很多情况下就直接打开了。这个时候用到的一个机制就是cookie。
2、session的一个场景是购物车,添加了商品之后客户端处可以知道添加了哪些商品,而服务器端如何判别呢,所以也需要存储一些信息,这里就用到了session。

COOKIE和SESSION有什么区别?
https://www.zhihu.com/question/19786827

session与cookie的区别
http://www.cnblogs.com/xulb597/archive/2012/07/02/2573252.html

Cookie和Session的区别
https://www.cnblogs.com/wswang/p/6062461.html


HTTP cookies
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies

HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的HTTP协议记录稳定的状态信息成为了可能。

除了name与value之外,Cookie 还具有其他几个常用的属性。每个属性对应一个getter方法与一个setter方法。Cookie类的所有属性如下所示。

  • String name:该Cookie的名称。Cookie一旦创建,名称便不可更改。
  • Object value:该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码。 比如用base64编码保存小图片。
  • int maxAge:该Cookie失效的时间,单位秒。如果为正数,则该Cookie在>maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1。
  • boolean secure:该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。
  • String path:该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”。
  • String domain:可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”。
  • String comment:该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明。 int version:该Cookie使>用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范。
  • httpOnly 指定该 Cookie 是否只能通过 HTTP 协议来访问,如果设置了这个属性,那么通过 JS 脚本是无法访问这个 Cookie 的。

当服务器收到 HTTP 请求时,服务器可以在响应头里面添加一个 Set-Cookie 选项。浏览器收到响应后通常会保存下 Cookie,之后对该服务器每一次请求中都通过 Cookie 请求头部将 Cookie 信息发送给服务器。另外,Cookie 的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。

服务器使用 Set-Cookie 响应头部向用户代理(一般是浏览器)发送 Cookie信息 Set-Cookie: <cookie名>=<cookie值>

Cookie 的生命周期可以通过两种方式定义:
1、会话期 Cookie
会话期 Cookie 是最简单的 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。会话期 Cookie 不需要指定过期时间(Expires)或者有效期(Max-Age)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期 Cookie 也会被保留下来,就好像浏览器从来没有关闭一样,这会导致 Cookie 的生命周期无限期延长。

2、持久性 Cookie
持久性 Cookie 的生命周期取决于过期时间(Expires)或有效期(Max-Age)指定的一段时间。
例如 Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
当 Cookie 的过期时间被设定时,设定的日期和时间只与客户端相关,而不是服务端。

有两种方法可以确保 Cookie 被安全发送,并且不会被意外的参与者或脚本访问:Secure 属性和 HttpOnly 属性。

Secure 属性

标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,因此可以预防 man-in-the-middle 攻击者的攻击。

HttpOnly 属性

JavaScript Document.cookie API 无法访问带有 HttpOnly 属性的 cookie;此类 Cookie 仅作用于服务器。例如,持久化服务器端会话的 Cookie 不需要对 JavaScript 可用,而应具有 HttpOnly 属性。此预防措施有助于缓解 跨站点脚本(XSS) 攻击。

Cookie的作用域

Domain

Path


上一篇 2019年运动记录

下一篇 领域驱动设计

阅读
评论
10.8k
阅读预计41分钟
创建日期 2019-02-21
修改日期 2023-12-05
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论