HTTP

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。HTTP,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

11.HTTP
11.1.介绍
  • 概念:Hyper Text Transfer Protocol 超文本传输协议

    • HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”
  • 传输协议:定义了客户端和服务器端通信时发送数据的格式

    1. 基于TCP/IP的高级协议
    2. 默认端口号:80(Https协议默认端口是443)
    3. 基于请求/响应模型的:一次请求对应一次响应
    4. 无状态的:每次请求之间相互独立,不能交互数据
  • 历史版本:

    • HTTP1.0:每一次请求响应都会建立新的连接
    • HTTP1.1:复用连接
  • 完整的HTTP事务

    1. 域名解析:在网络中,计算机只认识IP地址,不认识域名
      • 浏览器搜索自身的DNS缓存,看是否有对应的条目,如果有且没有过期则解析到此结束。
      • 如果没有找到对应的条目,那么Chrome会搜索操作系统自身的DNS缓存,如果找到且没过期则停止搜索解析到此结束.
      • 如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件,看有没有该域名对应的IP地址,如果有则解析成功。
      • 如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器发起域名解析请求,运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功
    2. 发起TCP的三次握手(网络编程中已经介绍过)
      • 拿到域名对应的IP地址后,User-Agent(一般是指浏览器)会以一个随机端口(1024 < 端口 < 65535)向服务器的WEB程序80端口发起TCP的连接请求。这个连接请求(原始的http请求经过TCP/IP4层模型的层层封包)到达服务器端后,进入到网卡,然后是进入到内核的TCP/IP协议栈,还有可能要经过Netfilter防火墙的过滤,最终到达WEB程序,建立了TCP/IP的连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接
    3. 发起HTTP请求,向IP地址对应主机对应端口号发送http请求报文
      • 在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
      • 在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接求。通常 的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
      • 进过TCP3次握手之后,浏览器发起了http的请求,使用http的GET方法,请求的URL是 / ,协议是HTTP/1.0。
    4. 服务器响应HTTP请求,其实质是将客户端发来的网络路径转换成服务器上的虚拟路径
      • 服务器端WEB程序接收到http请求以后,就开始处理该请求,处理之后就返回给浏览器html文件。
    5. 浏览器解析HTML代码,并反复请求HTML代码中的资源
      • 浏览器拿到index.html文件后,就开始解析其中的html代码,遇到js/css/image等静态资源时,就向服务器端去请求下载(会使用多线程下载,每个浏览器的线程数不一样),这个时候就用上keep-alive特性了,建立一次HTTP连接,可以请求多个资源,下载资源的顺序就是按照代码里的顺序,但是由于每个资源大小不一样,而浏览器又多线程请求请求资源,顺序并不一定是代码里面的顺序。
      • 浏览器在请求静态资源时(在未过期的情况下),向服务器端发起一个http请求(询问自从上一次修改时间到现在有没有对资源进行修改),如果服务器端返回304状态码(告诉浏览器服务器端没有修改),那么浏览器会直接读取本地的该资源的缓存文件。
    6. 浏览器对页面进行渲染并呈现给用户
11.2.HTTP请求报文
11.2.1.请求行
请求方式 请求url 请求协议/版本
GET /login.html HTTP/1.1
  • 请求方式:
    • HTTP协议常用的有2种
      • get(如果没有设置,默认情况下请求方式都是get):
        1. 请求参数会在地址栏中显示,拼接在url中。会封装到请求行中(HTTP协议)。
        2. 请求参数大小是有限制的,url的参数部分最多拼接1kb。
        3. 不太安全。
        4. get主要用来获取数据。
      • post:
        1. 请求参数不会再地址栏中显示。但是打开浏览器开发者模式可以看到。会封装在请求体中(HTTP协议)。
        2. 请求参数的大小没有限制。
        3. 较为安全。
        4. post主要用来提交数据。
    • 其他请求方式:
      • HEAD获取某个URI响应头信息,基本与GET相同但是不返回响应主体。
      • PUT通过提供的URI获取到特定的内容主体,如果存在则修改内容,如果不存在则创建。
      • DELETE通过URI删除指定内容
      • TRACE返回接受到的请求,用来查看数据经过中间服务器时发生了哪些变动
      • OPTIONS返回给定URL支持的所有HTTP方法
      • CONNECT要求使用SSL和TLS进行TCP通信
      • PATCH请求修改局部数据
11.2.2.请求头:
  • 客户端浏览器告诉服务器一些信息
  • 格式:请求头名称: 请求头值 (即键值对形式)
11.2.3.请求空行
  • 空行,就是用于分割POST请求的请求头,和请求体的。
11.2.4.请求体(正文):
  • 封装POST请求消息的请求参数的
11.3.请求信息字符串格式
  • Example:
POST /login.html	HTTP/1.1    //请求行,分为三部分,分别为,请求方式,请求资源,请求协议/版本
Host: localhost    //请求头,有若干个
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1
						//在请求头和请求体之间有一个空行,称为请求空行
username=zhangsan		//请求体



//请求cskaoyan官网
GET http://www.cskaoyan.com/forum.php HTTP/1.1
Host: www.cskaoyan.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
  • HTTP请求的细节
    • Accept:浏览器可接受的 MIME类型 / (大类型)/(小类型)
      • MIME:互联网将各种资源进行了一个分类,比如分成文本类、音频类、视频类、图像类,每个类型下面又有很多的子类型,
        • 如文本类型下面有html、txt
        • 音频下面有mp3、flac
        • 视频下面有mp4、mkv、avi
        • 图片下面有jpg、png、bmp
      • MIME用一个大类型/小类型的方式来表述互联网上面的任意的一个资源类型。
        • 如最常见的text/html;image/png;image/jpg;
    • Accept-Charset: 浏览器通过这个头告诉服务器,它支持哪种字符集
    • Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip
    • Accept-Language: 浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。 可以在浏览器中进行设置。
      • 其中的数字表示了某种语言的权值,1为最高,没有的话默认权值为1
      • 语句之间用逗号分割
    • Host:初始URL中的主机和端口
    • Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面(防盗链:防止他人盗取链接,统计工作:统计访问的信息)
    • Content-Type:内容类型
    • If-Modified-Since: 与浏览器缓存相关,表示自从某个时间以来,服务器文件内容是否发生了修改。服务器利用这个头与服务器的文件进行比对,如果一致,则告诉浏览器从缓存中直接读取文件。
    • User-Agent:浏览器类型。
    • Content-Length:表示请求消息正文(只有请求体不为空的时候才会出现)的长度 (一般用于文件上传)
    • Connection:表示是否需要持久连接。如果服务器看到这里的值为“Keep -Alive”,或者看到请求使用的是HTTP 1.1,HTTP 1.1默认进行持久连接
    • Date:Date: Mon, 22 Aug 2011 01:55:39 GMT请求时间GMT
    • Cookie:这是最重要的请求头信息之一 ,以后介绍
11.3.HTTP响应报文
  • 响应行
  • 响应头
  • 响应空行
  • 响应体
  • Example:
    HTTP/1.1 200 OK		//响应行,格式为HTTP版本号 状态码 原因叙述<CRLF>
    Server: Tengine		//若干个响应头
    Content-Type: text/html; charset=gbk
    Content-Length: 51527
    Connection: keep-alive
    Date: Tue, 23 Feb 2021 12:11:44 GMT
    Set-Cookie: cZBD_2132_sid=Q6gG3J; expires=Wed, 24-Feb-2021 12:11:44 GMT; Max-Age=86400; path=/
    Set-Cookie: cZBD_2132_lastact=1614082304%09forum.php%09; expires=Wed, 24-Feb-2021 12:11:44 GMT; Max-Age=86400; path=/
    Vary: Accept-Encoding
    Ali-Swift-Global-Savetime: 1614082304
    Via: cache31.l2cn3003[73,200-0,M], cache7.l2cn3003[74,0], kunlun6.cn1411[77,200-0,M], kunlun8.cn1411[78,0]
    X-Cache: MISS TCP_MISS dirn:-2:-2
    X-Swift-SaveTime: Tue, 23 Feb 2021 12:11:44 GMT
    X-Swift-CacheTime: 0
    Timing-Allow-Origin: *
    EagleId: af06eb9c16140823045625733e
    					//响应空行,下边是响应体,主要是给浏览器一个html页面用于展示给用户
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=gbk" />
    <title>王道论坛,专注于计算机考研的点点滴滴! .....省略后边
    
  • HTTP响应的细节
    • 响应行的原因叙述代码:
    • 状态码用于表示服务器对请求的各种不同处理结果和状态,它是一个三位的十进制数。响应状态码分为5类,使用最高位为1到5来进行分类如下所示:
      状态码 含义
      200~299 表示成功接收请求并已完成整个处理过程 200 OK 206
      300~399 (重定向)为完成请求,客户需进一步细化请求。例如,请求的资源已经移动一个新地址
      400~499 客户端的请求有错误
      500~599 服务器端出现错误
    • 常用状态码
      • 200(正常):表示一切正常,返回的是正常请求结果
      • 206:表示分段的请求OK
      • 301、302/307(临时重定向):指出被请求的文档已被临时移动到别处,此文档的新的URL在Location响应头中给出。(比如国外服务器跳转到国内)
      • 304(未修改):表示客户机缓存的版本是最新的,客户机可以继续使用它,无需到服务器请求。
      • 404(找不到):404服务器上不存在客户机所请求的资源。
        • 400:服务器不支持这种请求方式
      • 500(服务器内部错误):服务器端的程序发生错误
  • HTTP响应的细节
    • Location: 指示新的资源的位置
    • Server: apache tomcat 指示服务器的类型
    • Content-Encoding: gzip 服务器发送的数据采用的编码类型
    • Content-Length: 80 告诉浏览器正文的长度
    • Content-Language: zh-cn服务发送的文本的语言
    • Content-Type: text/html; 服务器发送的内容的MIME类型
    • Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT文件的最后修改时间
    • Refresh: 指示客户端刷新频率。单位是秒
  • Content-Disposition: attachment; filename=aaa.zip 指示客户端保存文件
    • Set-Cookie: SS=Q0=5Lb_nQ; path=/search 服务器端发送的Cookie,和请求头Cookie一起使用
    • Expires: 0:缓存相关,0指的是不缓存
    • Cache-Control: no-cache (1.1) :缓存相关,no-cache指的是不缓存
    • Connection: close/Keep-Alive :既可以放在请求里边,也可以放在响应里边
    • Date: Tue, 11 Jul 2000 18:23:51 GMT :时间
11.4.HTTPS
  • HTTPS = HTTP + Secure
  • HTTP的缺点:
    1. 通讯过程完全是透明的,不加密
    2. 不验证通讯另一方的身份(卖茶叶的)
    3. 还没有完整性的校验,比如请求报文或者响应报文被修改,也不会发现。
  • HTTPS相对于HTTP的改进:
    1. HTTPS采用加密算法来加密
      • 对称加密:加密和解密使用的是同一把密钥。加密解密速度比较快
      • 非对称加密:公钥进行加密,但是加密之后只可以用私钥来进行解密。速度比较慢
      • 实际上,在真实的HTTPS通讯过程中,使用的是混合加密。
        1. 客户端向服务端发起一个请求,服务器返回一个公钥给客户端
        2. 客户端拿到公开密钥后,通过对称加密随机生成一个共享密钥,并使用公钥将此共享密钥进行非对称加密(也就是用私有密钥加密)
        3. 客户端将共享秘钥发送给服务端,服务端拿到加密后的共享密钥后,用私有密钥进行解密获取到客户端真实的共享密钥
        4. 客户端和服务端通过共享密钥加密需要传输的文本内容,后续与服务端交互就是采用共享密钥加密解密来完成

          个人理解:实际上,这个混合加密方式,可以理解为,

          1. 首先,C(Client)向S(Sever)索要到了一把锁,而这把锁的钥匙只有S才有
          2. C拿到这把锁以后,又买了一把新锁,而这把新锁有两把钥匙,
          3. C买了个盒子,又买了一把新锁,并把新锁的其中一把钥匙放在了盒子里,用旧锁锁上,交给了S,自己留了一把新锁的钥匙
          4. S拿到旧锁,用自己的钥匙打开盒子上的旧锁,获得了C放在盒子里的,新锁的钥匙
          5. 从此以后,C和S就用新锁来传递信息
    2. HTTPS会验证通讯方的身份信息3
      • 采用的是证书。
    3. HTTPS会进行完整性校验
11.5.HTTP Example
public class WebServer {
    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(8090);
        
        while (true){
            Socket socket = serverSocket.accept();
            //InputStream、OutputStream都是抽象基类,原本是不能实例化的
            //实际上,getOutputStream()方法真正的返回类型是SocketOutputStream
            //相当于多态,所以才能父类引用指向子类
            InputStream cin = socket.getInputStream();

            new Thread(()-> {
                
                byte[] b = new byte[1024];
                
                //byte[] b = new byte[10];
                
                int len = 0 ;

                //while(len!=-1) {
                    try {
                        len = cin.read(b);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.out.print(new String(b, 0, len));
                //}
            }).start();
            
            cin.close();
        }
    }
}

输出结果如下:
    GET / HTTP/1.1
    Host: localhost:8090
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
    Sec-Fetch-Site: none
    Sec-Fetch-Mode: navigate
    Sec-Fetch-User: ?1
    Sec-Fetch-Dest: document
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
    Cookie: Idea-976a8fbc=b61a0e18-d64a-426c-8c22-0db2a6db5967
  • 对于此程序,做出如下解读
    • 所用方法:
      • ServerSocket类的API:public Socket accept():侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
      • Socket类的API:
        • public InputStream getInputStream():返回此套接字的输入流。 底层是SocketInputStream
        • public OutputStream getOutputStream():返回此套接字的输出流。 底层是SocketOutputStream
      • SocketInputStream继承来的方法:
        • public int read(byte[] b):从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。在某些输入可用之前,此方法将阻塞。
    • 对于两个阻塞方法,如果不采用多线程形式,假设accept接收到了端口的访问,但是没有接收到请求报文,read方法阻塞,这个时候如果还有请求访问,是无法接收到的,所以应该采用多线程形式。
    • 程序外层套一个while(true)循环,目的是为了持续监听端口请求,而在浏览器中输入localhost://8090,浏览器持续请求的过程中,while不断循环,而字节输入流不断地指向一个新的实例化的输入流对象,也就是说,其实在每次循环中,字节输入流读取只读取了一次,同时也只打印了一次。
    • 这里,没有采用循环读取,为什么也能读取到完整的请求报文?
      • 解释:因为byte数组足够大,可以一次读完所有请求报文(我们所测试的 localhost://8090 请求只有请求行和请求头,内容大概600字节左右,个人测试请求报文为601字节),所以当程序运行到if语句时,len的值为实际读到的字节数,因此直接输出即可。
      • 注意IO流read方法的返回值问题,尤其注意,当剩余字符不够一次读取的时候,read方法究竟返回什么(IO流里已经介绍)
      • 验证测试:将这个数组大小改为10,就可以看到控制台只打印了10个字符,证明确实没有循环读取,也可以打断点调试

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181056.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!