## # http post 传送文件详解(转载
)

### # 首先客户端链接 192.168.24.56 后, 应该发送如下 http 请求：

    POST/logsys/home/uploadIspeedLog!doDefault.html HTTP/1.1

    Accept: text/plain, _/_
    Accept-Language: zh-cn
    Host: 192.168.24.56
    Content-Type:multipart/form-data;
    boundary=-----------------------------7db372eb000e2
    User-Agent: WinHttpClient
    Content-Length: 3693
    Connection: Keep-Alive
    -------------------------------7db372eb000e2
    Content-Disposition: form-data; name="file"; filename="kn.jpg"
    Content-Type: image/jpeg
    (此处省略 jpeg 文件二进制数据...）
    -------------------------------7db372eb000e2--

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

此内容必须一字不差，包括最后的回车，红色字体部分就是协议的头。给服务器上传数据时，并非协议头每个字段都得说明，其中，`content-type`是必须的，它包括一个类似标志性质的名为`boundary`的标志，**它可以是随便输入的字符串。对后面的具体内容也是必须的。它用来分辨一段内容的开始。**Content-Length: 3693 ，这里的 3693 是要上传文件的总长度。绿色字体部分就是需要上传的数据，可以是文本，也可以是图片等。数据内容前面需要有 `Content-Disposition`, `Content-Type` 以及 `Content-Transfer-Encoding` 等说明字段。最后的紫色部分就是协议的结尾了。

`注意这一行`：

`Content-Type: multipart/form-data;` `boundary=---------------------------7db372eb000e2`
根据 `rfc1867`, `multipart/form-data` 是必须的.
`---------------------------7db372eb000e2` 是分隔符，分隔多个文件、表单项。其中 `b372eb000e2`是即时生成的一个数字，用以确保整个分隔符不会在文件或表单项的内容中出现。Form 每个部分用分隔符分割，分隔符之前必须加上"--"着两个字符(即--{boundary})才能被 http 协议认为是 Form 的分隔符，表示结束的话用在正确的分隔符后面添加"--"表示结束。

前面的 `---------------------------7d` 是 `IE` 特有的标志,`Mozila` 为`---------------------------71`

每个分隔的数据的都可以用 `Content-Type` 来表示下面数据的类型，可以参考 `rfc1341` (http://www.ietf.org/rfc/rfc1341.txt
)

`例如` ：`Contect-Type:image/jpeg` 表示下面的数据是 `jpeg` 文件数据

`转载`：http://www.cnblogs.com/liangbin/articles/2117288.html

*******************************************************************************************************************************

### # `HTTP 响应`

在接收和解释请求消息后，服务器会返回一个 `HTTP` 响应消息。
与 `HTTP` 请求类似，`HTTP` 响应也是三个部分组成，分别是：
状态行、消息报头、响应正文。
`状态行`：
状态行由协议版本、数字形式的状态代码、及相应的状态描述，各元素之间以空格分隔。

`格式`: HTTP-Version Status-Code Reason-Phrase CRLF
`例如`: HTTP/1.1 200 OK \r\n

`状态代码`：
状态代码由 `3` 位数字组成，表示请求是否被理解或被满足。

`状态描述：`
状态描述给出了关于状态代码的简短的文字描述。

状态代码的第一个数字定义了响应的类别，后面两位没有具体的分类。
第一个数字有五种可能的取值：

- 1xx: 指示信息—表示请求已接收，继续处理。
- 2xx: 成功—表示请求已经被成功接收、理解、接受。
- 3xx: 重定向—要完成请求必须进行更进一步的操作。
- 4xx: 客户端错误—请求有语法错误或请求无法实现。
- 5xx: 服务器端错误—服务器未能实现合法的请求。

状态代码 | 状态描述 | 说明
--- | --- | ---
200 | OK | 客户端请求成功
400 | Bad | Request 由于客户端请求有语法错误，不能被服务器所理解。
401 | Unauthonzed | 请求未经授权。这个状态代码必须和 `WWW-Authenticate` 报头域一起使用
403 | Forbidden | 服务器收到请求，但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 | Not Found | 请求的资源不存在，例如，输入了错误的 `URL`。
500 | Internal Server Error | 服务器发生不可预期的错误，导致无法完成客户端的请求。
503 | Service Unavailable | 服务器当前不能够处理客户端的请求，在一段时间之后，服务器可能会恢复正常。

#### # HTTP消息

`HTTP消息`由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始行，消息报头(可选的)，空行(只有`CTLF`的行)，消息正文(可选的)组成。
对于请求消息，开始行就是请求行。
对于响应消息，开始行就是状态行。

#### # 消息报头

HTTP 消息报头包括普通报头、请求报头、响应报头、实体报头。
每一个报头域都是由(名字＋":"＋空格＋值)组成,消息报头域的名字是大小写无关的。

#### # 普通报头

在普通报头中，有少数报头域应用于所有的请求和响应消息，但并不用于被传输的实体，这些报头域只用于传输的消息。

常用的普通报头域：`Cache-Control`,`Date`,`Connection`,`Pragma`.

#### # 请求报头

请求报头允许客户端向服务器端传递该请求的附加信息以及客户端自身的信息。
`常用的请求报头域：`

`Accept`

- `Accept`请求报头域用语指定客户端接受哪些类型的信息。例如：`Accept`: `image/gif`,表明客户端希望接受`GIF图象格式`的资源；`Accept`: `text/html`,表明客户端希望接受`html文本`

`Accept-Charset`

- `Accept-Charset`请求报头域用于指定客户端接受的字符集。例如：`Accept-Charset`: `ios-8859-1`,`gb2312`。如果在请求消息中没有设置这个域，缺省是任何字符集都可以接受。

`Accept-Encoding`

- `Accept-Encoding`请求报头域类似`Accept`，但是它是用于指定可接受的内容编码。例如：`Accept-Encoding`: `gzip`, `deflate`。如果请求消息中没有设置这个域，服务器假定客户端对各种内容编码都可接受。

`Accept-Language`

- `Accept-Language`请求报头域类似于`Accept`,但是它是用于指定一种自然语言。例如：`Accept-Language`: `zh-cn`。如果请求消息中没有设置这个域，服务器假定客户端对各种语言都可接受。

`Authorization`

- `Authorization`请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时，如果收到服务器的响应代码为`401`(未授权)，可以发送一个包含`Authorization`请求报头域的请求，要服务器对其进行验证。

`Host`

- `Host`请求报头域主要用于指定被请求资源的`Internet`主机和端口号，它通常是从`HTTP URL`中提取出来的。 例如:http://www.sunxin.org/index.html。浏览器发送的请求消息中，就会包含`Host`请求报头域，如下：Host: www.sunxin.org
- 后面没有跟端口号，表明使用的是缺省端口号`80`，如果端口号不是`80`，那么就要在主机名后面加上一个冒号("😊,然后接上端口号，例如：
- `Host`: `www.sunxin.org:8080`。 要注意的是，在发送`HTTP`请求的时候，这个报头域是必须的。
  `User-Agent`
- `User-Agent`允许客户端将它的操作系统浏览器和其他属性告诉服务器。我们上网登陆论坛的时候，往往看到些欢迎信息，其中列出了你的操作系统的名称和版本等等信息。原因是：服务器从`User-Agent`请求报头域中获取的这些信息，自己编写浏览器可以不用这个请求报头域。服务器就无法得知了。

### # `响应报头`

响应报头允许服务器传递不能放在状态行中的附加响应信息，以及关于服务器的信息和对`Request-URI`所标识的资源进行下一步访问的信息。
常用的响应报头域：
`Location`

- `Location`响应报头域用于重定向接受者到一个新的位置。例如：客户端所请求的页面已不存在原先的位置，为了让客户端重定向到这个页面新的位置，服务器端可以发回`Location`响应报头后使用重定向语句，让客户端去访问新的域名所对应的服务器上的资源。当我们在`JSP`中使用重定向语句的时候，服务器端向客户端发回的响应报头中，就会有 Location 响应报头域。下面是`Location`响应报头域的一个例子：`Location`:`http://www.sunxin.org`

`Server`

- `Server`响应报头域包含了服务器用来处理请求的软件信息。它和`User-Agent`请求报头域是相对应的，前者发送服务器端软件的信息，后者发送客户端软件(浏览器)和操作系统的信息。下面是`Server`响应报头域的一个例子：`Server`: `Apache-Coyote/1.1`

`WWW-Authenticate`

- `WWW-Authenticate`响应报头域必须被包含在`401`(未授权的)响应消息中，这个报头域和前面讲到的`Authorization`请求报头域是相关的，当客户端收到`401`响应消息，就要决定是否请求服务器对其进行验证。如果要求服务器对其进行验证，就可以发送一个包含了`Authorization`报头域的请求，下面是 WWW-Authenticate 响应报头域的一个例子：`WWW-Authenticate`: `Basic realm="Basic Auth Test!"`

从这个响应报头域，可以知道服务器端对我们所请求的资源采用的是基本验证机制。

`实体报头`

- 请求和响应消息都可以传送一个实体。一个实体由实体报头域和实体正文组成，大多数情况下，实体正文就是请求消息中的请求正文或者响应消息中的响应正文。但是在发送时，并不是说实体报头域和实体正文要在一起发送，例如：有些响应可以只包含实体报头域。实体就好象我们写的书信，在信中，我们可以写上标题，加上页号等，这部分就相当于是实体报头域，而我们所写的书信的内容，就相当于实体正文。前面说讲的普通报头、请求报头、响应报头我们可以看成是写在信封上的邮编、接收者，发送者等内容。
  实体报头定义了关于实体正文(例如：有无实体正文)和请求所标识的资源的元信息。
  所谓元信息，是指描述其他信息的信息。

`常用的实体报头域：`

`Content-Encoding`

- `Content-Encoding`实体报头域被使用作媒体类型的修饰符，它的值指示了已经被应用到实体正文的附加内容编码，因而要获得`Content-Type`报头域中所引用的媒体类型，必须采用相应的解码机制。`Content-Encoding`主要用语记录文档的压缩方法，下面是它的一个例子：`Content-Encoding`: `gzip`。如果一个实体正文采用了编码方式存储，在使用之前就必须进行解码。

`Content-Language`

- `Content-Language`实体报头域描述了资源所用的自然语言。Content-Language 允许用户遵照自身的首选语言来识别和区分实体。如果这个实体内容仅仅打算提供给丹麦的阅读者，那么可以按照如下的方式设置这个实体报头域：`Content-Language`: `da`。
- 如果没有指定`Content-Language`报头域，那么实体内容将提供给所以语言的阅读者。

`Content-Length`

- Content-Length 实体报头域用于指明正文的长度，以字节方式存储的十进制数字来表示，也就是一个数字字符占一个字节，用其对应的 ASCII 码存储传输。
- 要注意的是：这个长度仅仅是表示实体正文的长度，没有包括实体报头的长度。

`Content-Type`

- Content-Type 实体报头域用语指明发送给接收者的实体正文的媒体类型。例如：
- Content-Type: text/html;charset=ISO-8859-1
- Content-Type: text/html;charset=GB2312

`Last-Modified`

- Last-Modified 实体报头域用于指示资源最后的修改日期及时间。

`Expires`

- `Expires`实体报头域给出响应过期的日期和时间。通常，代理服务器或浏览器会缓存一些页面。当用户再次访问这些页面时，直接从缓存中加载并显示给用户，这样缩短了响应的时间，减少服务器的负载。为了让代理服务器或浏览器在一段时间后更新页面，我们可以使用`Expires`实体报头域指定页面过期的时间。当用户又一次访问页面时，如果`Expires`报头域给出的日期和时间比`Date`普通报头域给出的日期和时间要早(或相同)，那么代理服务器或浏览器就不会再使用缓存的页面而是从服务器上请求更新的页面。不过要注意，即使页面过期了，也并不意味着服务器上的原始资源在此时间之前或之后发生了改变。
- `Expires`实体报头域使用的日期和时间必须是`RFC 1123`中的日期格式，例如：`Expires: Thu, 15 Sep 2005 16:00:00 GMT`
- `HTTP1.1`的客户端和缓存必须将其他非法的日期格式(也包括 0)看作已过期。例如，为了让浏览器不要缓存页面，我们也可以利用`Expires`实体报头域，设置它的值为`0`，如下(`JSP`)：`response.setDateHeader("Expires",0)`;

`除掉注释的部分就是一个完整的包，向/user/tmpUpload.php上传了一个文件。`

     =========http头==========
      POST   /user/tmpUpload.php   HTTP/1.1
      Content-Type:   multipart/form-data;
      boundary=---------------------------7d53b9297030e
      Content-Length:   1017

      -----------------------------7d53b9297030e
      Content-Disposition:   form-data;
      name="upload";
      filename="C:\Documents.and.Settings\hwy\桌面\attachment"
      Content-Type:   p

                111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              11111111111111111111111111111111111111111
              111111111111111111111111111111111111

    -----------------------------7d53b9297030e--

        ===========结束============

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
30
31

本文来自 xyz_1991 的 CSDN 博客 ，全文地址请点击：https://blog.csdn.net/xyz_1991/article/details/51320578?utm_source=copy