HTTP相关总结

HTTP/1.1

一、简介

       HTTP协议:超文本传输协议(HyperText Transfer Protocol, HTTP),使用TCP作为运输层协议。HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。HTTP 是一个无状态协议,但是web站点往往希望能够识别用户,因此有了cookie和session。

二、HTTP报文格式

 

   Client request:
     GET /hello.txt HTTP/1.1
     User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
     Host: www.example.com
     Accept-Language: en, mi


   Server response:
     HTTP/1.1 200 OK
     Date: Mon, 27 Jul 2009 12:28:53 GMT
     Server: Apache
     Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
     ETag: "34aa387-d-1568eb00"
     Accept-Ranges: bytes
     Content-Length: 51
     Vary: Accept-Encoding
     Content-Type: text/plain

     Hello World! My payload includes a trailing CRLF.

 

1、HTTP请求报文 

image.png

 

请求行:

     请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。

HTTP协议的请求方法有GET、POST、HEAD、PUT、DELETE、TRACE等。

注意:HTTP协议本身并没有限制URL的长度,实际中URL长度限制是实现http协议的客户端(浏览器等)和服务器限制的。

 

首部(Header Fields)

请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的首部头(包括请求头或者响应头)有:

User-Agent:产生请求的浏览器类型。

Accept:客户端可识别的内容类型列表。

Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。

Cookie:该请求域名下的cookie值。

Set-Cookie:_security_token=51568727949026296;Path=/;Domain=.dasouche-fin.net;Max-Age=600000。

Content-Type:请求的与实体对应的MIME信息,application/x-www-form-urlencoded、text/html;charset=UTF-8等。

Connection:keep-alive,持久连接,HTTP/1.0需要显示声明,HTTP/1.1默认开启。关闭:Connection:close。

Referer:该首部包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer 首部识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。

Accept-Language:浏览器可接受的语言,比如Accept-Language:en,zh。

Accept-Encoding:客户端能够理解的内容编码方式——通常是某种压缩算法——进行通知,通过内容协商的方式,服务端会选择一个客户端提议的方式,使用并在响应报文首部Content-Encoding中通知客户端该选择。需要注意的是,服务器端并不强制要求一定使用何种压缩模式。

注意:有字符集限制,中文汉字可能需要URLEncoder.encode、URLDecoder.decode

 

实体主体:(Message Body)

实体主体是可选的,如GET时,实体主体为空;Post请求时使用。

 

2、HTTP响应报文 

image.png

与请求报文类似,只是请求行与状态行的不同。在RFC中,请求行/状态行称为起始行(Start Line,状态值翻译为“短语”(reason-phrase)更好一些.

状态码:There are five values for the first digit:

   o  1xx (Informational): The request was received, continuing process

   o  2xx (Successful): The request was successfully received, understood, and accepted

   o  3xx (Redirection): Further action needs to be taken in order to complete the request

   o  4xx (Client Error): The request contains bad syntax or cannot be fulfilled

   o  5xx (Server Error): The server failed to fulfill an apparently valid request

      在网络世界中,浏览器绝对不是唯一的 HTTP 客户端工具,上面图片中提到的 Postman等工具也是HTTP客户端实现的一种,其实还有更多,只不过浏览器的使用最为广泛而已;明确不能将浏览器对HTTP协议的实现,当做了HTTP协议本身。

 

三、跨域问题

1、跨域问题的产生

        跨域问题的产生原因:浏览器的同源策略。为什么要这个策略?安全问题,缺少易受到跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等攻击。

所谓同源是指:协议、域名、端口相同。

image.png

参考:

image.png

注意:如果一个主机IP上有多个域名应用,在跨域问题上,域仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。

 

2、解决方案

1、原生js的JSONP

       由于同源策略,一般来说位于server1.example.com的网页无法与 server2.example.com的服务器沟通,而HTML的 <script>元素是一个例外。利用 <script>元素的这个开放策略,网页可以得到从其他来源动态产生的JSON数据,而这种使用模式就是所谓的 JSONP。

演示代码:

服务端:

 

const url = require('url');

require('http').createServer((req, res) => {
    const data = {
        x: '隔壁超市薯片半价啦'
    };
    const callback = url.parse(req.url, true).query.callback
    res.writeHead(200);
    //回调原页面上函数处理返回结果
    res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, 'localhost');
console.log('服务器已启动...');

浏览器端:http://local.dasouche-fin.net:8086/index.jsp

 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <script>
      function jsonpCallback(data){
          alert('跨域成功!'+data.x)
      }
  </script>
<script src="http://localhost:3000/?callback=jsonpCallback"></script>
</body>
</html>

缺点:

只能是get请求,因为<script >是GET请求,不安全可能会遭受XSS攻击。

 

2、jQuery的jsonp形式

jsonp技术跟ajax没有任何关系,只不过jQuery将jsonp和ajax技术做了结合。

有很多种写法,只列出一种:

 

$.ajax({
    url:'http://外域.com/xxx.php',
    dataType:"jsonp",
    jsonp: "callback",
    jsonpCallback:"ooo",
    success:function(data){
        console.log(data);
    }
});

 

 

3、跨域资源共享 CORS

       CORS(Cross-Origin Resource Sharing)是一种机制(W3C 标准),它使用额外的HTTP 头来告诉浏览器  让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源,需要浏览器和服务端都支持才行。

 

3.1 简单请求

使用下列方法之一:

GET

HEAD

POST

HTTP的头信息不超出以下几种字段:

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

Content-Type 的值仅限于下列三者之一:

text/plain

multipart/form-data

application/x-www-form-urlencoded

请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

请求中没有使用 ReadableStream 对象。

 

简单请求流程:

image.png

分别查看请求报文和响应报文:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61 
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

 

 

3.2 非简单请求

      非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。

      1、非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

      2、服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

      3、如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出跨域报错信息。

      4、一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

 

非简单请求流程:

 

image.png

预检请求的请求报文和响应报文:

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

预检请求完成之后,发送实际请求报文和响应报文:

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache

<?xml version="1.0"?><person><name>Arun</name></person>



HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]

 

3.3 CORS相关首部

Request headers:

  • Origin:

      指示了请求来自于哪个站点。该字段仅指示服务器名称,并不包含任何路径信息。

 

  • Access-Control-Request-Method:

     请求首部  Access-Control-Request-Method 出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪种  HTTP 方法。因为预检请求所使用的方法总是 OPTIONS ,与实际请求所使用的方法不一样,所以这个首部是必要的。

 

  • Access-Control-Request-Headers

      请求首部  Access-Control-Request-Headers 出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪些请求首部。如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

 

Response headers:

  • Access-Control-Allow-Origin

      响应头指定了该响应的资源是否被允许与给定的origin共享。该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

 

  • Access-Control-Allow-Methods

      该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

 

  • Access-Control-Allow-Credentials

     CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

 

  • Access-Control-Expose-Headers

     该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

 

  • Access-Control-Max-Age

      该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

  • Access-Control-Allow-Headers

       如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

 

CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

 

4、Nginx反向代理

正向代理 和反向代理 ? ?

......

 

 

四、相关文档

HTTP/1.1 RFC文档:https://tools.ietf.org/html/rfc7230#section-2.7.1

Cookie RFC文档:https://tools.ietf.org/html/rfc6265#section-4.2

XSS攻击介绍文档:https://tech.meituan.com/2018/09/27/fe-security.html

CSRF介绍文档:https://tech.meituan.com/2018/10/11/fe-security-csrf.html
CORS文档:https://www.w3.org/TR/cors/
                    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章