java进阶-java与http

1.引言

我们在日常使用springMVC框架开发项目,习惯从Request和Header获取客户端传递数据,springMVC是基于Servlet的封装,Servlet容器如Tomcat来支撑,这些都是基于Http协议来工作的,导致我们对Http协议底层并不理解,这导致我们在异构系统通信、文件上传,他们的数据流程等搞不清楚,本文就http协议与java之间的关系做深度阐述,帮助大家理解到一些底层技术,在一些特殊业务处理里做到灵活应用。

2.http协议理解

2.1 定义

HTTP 协议全称为 Hypertext Transfer Protocol,即超文本传输协议,是互联网上应用最为广泛的一种网络传输协议。HTTP 协议定义了客户端(Browser)与服务器之间的通信规范,以实现对各种资源(如 HTML 页面、图像、音频、视频等)的传输和访问。

HTTP(Hypertext Transfer Protocol)即超文本传输协议,是一种用于传输超文本的应用层协议。HTTP协议建立在TCP/IP协议之上,主要用于Web浏览器与Web服务器之间的数据交换。

2.2 http特点

HTTP协议的主要特点:

1、支持客户/服务器模式。

2、简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。

3、灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。

4、无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

5、无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

2.3 http请求

2.3.1 HTTP请求和响应全步骤

在这里插入图片描述

(一)DNS域名解析

我们输入域名如www.baidu.com最终都要解析成IP:
(1)如果我们通过浏览器访问过,一般会被浏览器缓存下来,所以第一步从缓存里查询
(2)再从本地host文件里查询
(3)没有找到,都向DNS服务器发起请求,获得IP

(二)TCP连接-三次握手

TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息
在这里插入图片描述
第一次握手:
建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;

第二次握手:
服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;

第三次握手:
客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

为什么要三次握手

为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。

具体例子:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”

(三)请求和响应

TCP建立连接后,客户端和服务器端就可以通信了。
(1)发起http请求
请求是一个url连接,可以携带相关信息
(2)服务器端响应
获取客户端请求后,把相应的数据按照一定格式反馈给客户端
(3)客户端渲染
客户端拿到数据后,就可以渲染,通过浏览器等展现给用户

(四)TCP关闭-四次会受

Http是无状态的,每次访问后都会断开连接,和连接TCP对应,这里需要四次报文传递才会关闭连接

2.3.2HTTP请求消息报文-Request

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:
请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。

–请求行:包含用于请求的方法,请求URI和HTTP版本。
–请求首部字段
–通用首部字段
–实体首部字段
–其它

在这里插入图片描述
举个栗子,浏览器地址栏输入www.baidu.com,打开控制台,查看Request Headers,看到如下信息:

    GET / HTTP/1.1
    Host: www.baidu.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/53.0.2785.143 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Referer: https://www.baidu.com/s?wd=HTTP%20%E5%8D%8F%E8%AE%AE%E6%9C%89%E5%87%A0%E7%A7%8D%E5%92%8C.....
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: zh-CN,zh;q=0.8
    Cookie: BIDUPSID=670A04B660AAF2716D3120BEAF946A11; BAIDUID=2454D4....
    RA-Ver: 3.0.8
    RA-Sid: CA623F7A-20150914-060054-2b9722-5fde41
  • 第一行为请求行:
    GET / HTTP/1.1 方法是GET,协议版本http1.1

  • HOST:
    请求资源所在服务器

  • Connection keep-alive:
    一般情况下,一旦web服务器向浏览器发送了请求数据,他就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了Connection:keep-alive,则TCP连接在发送后仍将保持打开状态,于是,浏览器可以继续通过相同的连接发送请求,保持连接节省了为每个请求建立新连接所需要的时间,还节约了网络带宽。

  • User-Agent:
    客户端程序的信息,就是我发送请求的浏览器信息。

  • Accept:
    列出了浏览器可以接收的媒体数据类型:
    文本文件:text/html, text/palin,text/css,application/xhtml+xml…
    图片文件:image/jpeg, image/gif, image/png…
    视频文件: video/jpeg, video/quicktime…
    等。

  • Accept-Encoding:
    是浏览器用来告知服务器它能够支持的内容编码及内容编码的优先级顺序,可一次性指定多种内容编码。gzip:有文件压缩程序gzip生成的编码格式。deflate:组合使用zlib格式和deflate压缩算法生成的编码格式。sdch: Shared Dictionary Compression over HTTP字典压缩算法。

  • Accept-Language:
    告知服务器浏览器能够处理的自然语言集(中文、英文等)。zh-CN中文简体。

  • Cookie:
    -浏览器记录的用户相关信息。

  • Content-Type:
    非常重要的前短端交互字段,有application/json和application/x-www-form-urlencoded两种类型,下面详解

在这里插入图片描述

2.3.3 HTTP响应消息-Response

–状态行
–响应首部字段
–通用首部字段
–实体首部字段
–其他

浏览器控制台给出了相应的Reponse Headers:

HTTP/1.1 200 OK
Server: bfe/1.0.8.18
Date: Mon, 16 Jan 2017 06:35:24 GMT
Content-Type: text/html;charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: private
Expires: Mon, 16 Jan 2017 06:35:24 GMT
Content-Encoding: gzip
X-UA-Compatible: IE=Edge,chrome=1
Strict-Transport-Security: max-age=172800
BDPAGETYPE: 2
BDQID: 0xe0042a0200002ea3
BDUSERID: 252528851
Set-Cookie: BDSVRTM=104; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=21767_1446_21111_18133_19898_20718; path=/; domain=.baidu.com
Set-Cookie: __bsi=17204004216256107848_00_0_I_R_105_0303_C02F_N_I_I_0; expires=Mon, 16-Jan-17 06:35:29 GMT; domain=www.baidu.com; path=/
  • 第一行状态行:
    给出了状态码200,表示请求已被正常处理,这个是非常重要的判断码,后面详解。

  • Server:
    这是服务器用来告诉客户端当前服务器上安装的HTTP服务器应用程序的信息,可能包含服务器上的软件应用名称,版本号等。

  • Content-Type:
    此字段标明了服务器返回给浏览器的实体内容的类型是text/html,charset为UTF-8。这部分与请求头中的Accept相对应,后面还有详细讲解。
    请求体的MIME类型,MIME类型:描述消息内容类型的因特网标准,常见的有application/json、image/jpeg、application/octet-stream等

  • Transfer-Encoding:
    chunked 表示输出的内容长度不能确定,普通的静态页面、图片之类的基本上都用不到这个。动态页面中可能会用到。

  • Cache-Control:
    缓存控制,默认值为private,表示内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存)。

  • Expires:
    告知客户端资源失效的日期。当浏览器看到响应中有一个Expires头时,它会和相应的组件一起保存到其缓存中,只要组件没有过期,浏览器就会使用缓存版本而不会进行任何的HTTP请求。Expires设置的日期格式必须为GMT(格林尼治标准时间)。

  • X-UA-Compatible:
    设置浏览器兼容模式。 IE=Edge 指定IE浏览器以最新的标准来渲染页面,chrome=1 则可以激活Chrome Frame,将允许站点在使用了谷歌浏览器内嵌框架(Chrome Frame)的客户端渲染,对于没有使用的,则没有任何影响
    在这里插入图片描述

一个简单的respnse相应报文:
在这里插入图片描述

2.3.4 HTTP报文主体部分

1.向request的Header写入键值对

用ajax写入键值

 /***
     方法1:提交方式不是get post而是head
     **/
    function tt(){
        $.ajax(
            {
                headers: {
                    // 把键值对放到请求头中
                    "authentication":"mimi",
                    "RequestToken": "kiss"
                },
                'type': 'head',  //类型为head
                'url': '/webdemo/hello-servlet',
                'success': function (data, status, xhr) {
                    alert(xhr.getResponseHeader("ResponseToken"))
                }
            })
    }


    /**
     *方法2:beforeSend方法写入
     */
    function saveAjaxComm(targetUrl,formSerialize){
        $.ajax({
            type: "post",
            url: targetUrl,
            data: formSerialize,
            dataType: "html",
            async:true,//设置为异步
            beforeSend: function(xhr) {  //设置header
                xhr.setRequestHeader("authentication", "mimi");
                xhr.setRequestHeader("RequestToken", "kiss");
            },
            success: function(data){

             alert("ok");

            },
            error:function(XMLHttpRequest, textStatus, errorThrown){

                alert("保存失败:"+XMLHttpRequest.responseText);
            }


        });
    }

java接收

		 //接收请求头中的token并传递给变最RequestToken
        String RequestToken=request.getHeader("RequestToken");
        System.out.println("RequestToken==="+RequestToken);
        //写入
        response.addHeader("ResponseToken","responseToken value for token latter22");

查看IE的调试
在这里插入图片描述

3.Request主体

reuest的主体就是传递到后端的数据,数据格式和Content-Type有很大关系,后面详解
在这里插入图片描述
在这里插入图片描述

4.Response的主体

在这里插入图片描述

2.3.6 HTTP状态码

在客户端发送请求报文给服务器后,服务器会发送响应报文,响应报文中头部状态行中有一个十分重要的标识就是状态码,原来表示服务器对客户端的响应结果,如 200 就代表响应成功,这里的状态码可以分为几类:

状态码的第一位数字定义响应的类别。 后两位数字没有任何分类作用。可以分为5个类别:

1xx:信息状态码,收到请求,继续进行;
2xx:请求成功接收;
3xx:重定向,必须采取进一步措施才能完成请求;
4xx:客户端错误,请求包含错误语法,或者不能被完成;
5xx:服务器错误,服务器无法完成看似有效的请求;

状态码描述详细说明
101Switching Protocol该代码是响应客户端的 Upgrade 标头发送的,并且指示服务器也正在切换的协议。
200OK请求成功
204No Content服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。用这个状态码区分成功状态下又返回内容和没返回内容的响应。
206Partial Content服务器已经成功处理了部分 GET 请求。通过HTTP的分块下载,获取资源的部分时返回。该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。206状态码通常会携带Content-Range,用于表示报文里面body数据的具体范围。

3xx:重定向,必须采取进一步措施才能完成请求;

状态码描述详细说明
301Moved Permanently永久重定向,将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。
302Found临时重定向,客户端下次应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。
304Not Modified如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304 响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。

4xx:客户端错误,请求包含错误语法,或者不能被完成;

状态码描述详细说明
400Bad Request语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。
401Unauthorized当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。
403Forbidden服务器已经理解请求,但是拒绝执行它。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。
404Not Found请求失败,请求所希望得到的资源未被在服务器上发现。究竟是不是真的资源不存在呢?还得看程序是怎么写的。
405Method Not Allowed请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。
408Request Timeout请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改
409Conflict由于和被请求的资源的当前状态之间存在冲突,请求无法完成。
413Payload Too Large请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。
429Too Many Requests用户在给定的时间内发送了太多请求(“限制请求速率”)。
431Request Header Fields Too Large请求头字段太大( Request Header Fields Too Large)

5xx:服务器错误,服务器无法完成看似有效的请求;

状态码描述详细说明
500Internal Server Error服务器遇到了不知道如何处理的情况。通常用来捕获服务器异常,统一返回500,避免输出详细错误堆栈给别人利用。
501Not Implemented此请求方法不被服务器支持且无法被处理。只有GET和HEAD是要求服务器支持的,它们必定不会返回此错误代码。
502Bad Gateway此错误响应表明服务器作为网关需要得到一个处理这个请求的响应,但是得到一个错误的响应。
503Service Unavailable服务器没有准备好处理请求。 常见原因是服务器因维护或重载而停机。
504Gateway Timeout当服务器作为网关,不能及时得到响应时返回此错误代码。

2.4 HTTP 请求方法

2.4.1 请求URL介绍

URL (Uniform Resource Locator 统一资源定位符),互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
  URI的结构:

在这里插入图片描述
scheme:表示协议名,比如http, https, file等等。后面必须和://连在一起。

user:   passwd@ 表示登录主机时的用户信息,不过很不安全,不推荐使用,也不常用。

host:  port表示主机名和端口。

path: 表示请求路径,标记资源所在位置。

query: 表示查询参数,为key=val这种形式,多个键值对之间用&隔开。

fragment:表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应的位置。

在这里插入图片描述
最常用的pet post put head delete

2.4.1 GET方法

GET 是最常用的 HTTP 方法,常用于获取服务器上的某个资源。
三种主要方位形式:
1.访问地址。如www.baidu.com
2.带参数。如www.baidu.com?name=jzk
3.form表单的提交方法为get

GET 请求的特点:

1.首行里面的第一个部分就是 GET
2.URL 里面的 query string 可以为空,也可以不为空 %E8%9B%8B%E7%B3%95
3.GET 请求的 header 有若干个键值对结构
4. GET 请求的 body 一般是空的

在这里插入图片描述

2.4.2 POST 方法

POST 方法也是一种常见的方法,多用于提交用户输入的数据给服务器(如登录页面)。

POST 请求的特点:

1.首行第一个部分就是 POST
2.URL 里面的 query string 一般是空的
3.POST 请求的 header 里面有若干个键值对
4.POST 请求的 body 一般不为空(body 的具体数据格式,由 header 中的 Content-Type 来描述; body 的具体数据长度,由 header 中的 Content-Length 来描述

普通post表单提交
在这里插入图片描述
json对象
在这里插入图片描述

2.4.3 GET与POST区别

GET 和 POST 其实没有本质区别,使用 GET 的场景完全可以使用 POST 代替,使用 POST 的场景一样可以使用 GET 代替。但是在具体的使用上,还是存在一些细节的区别:

  • GET 习惯上会把客户端的数据通过 query string 来传输(body 部分是空的);POST 习惯上会把客户端的数据通过 body 来传输(query string 部分是空的)

  • GET 习惯上用于从服务器获取数据;POST 习惯上是客户端给服务器提交数据

  • 一般情况,程序员会把 GET 请求的处理,实现成“幂等”的;对于 POST 请求的处理,不要求实现成“幂等”

  • GET 请求可以被缓存,可以被浏览器保存到收藏夹中;POST 请求不能被缓存

2.4.4 HEADER

header 的整体格式是键值对结构,每个键值对占一行,键和值之间使用 冒号+空格 进行分割
在这里插入图片描述

自定义head值

/***
     方法1:提交方式不是get post而是head
     **/
    function tt(){
        $.ajax(
            {
                headers: {
                    // 把键值对放到请求头中
                    "authentication":"mimi",
                    "RequestToken": "kiss"
                },
                'type': 'head',  //类型为head
                'url': '/webdemo/hello-servlet',
                'success': function (data, status, xhr) {
                    alert(xhr.getResponseHeader("ResponseToken"))
                }
            })
    }

在这里插入图片描述

2.5 输入输出的contentType配置

2.5.1 Request 输入

Content-Type 有以下三种请求中的数据格式:

  • application/x-www-form-urlencoded
    这是 form 表单提交的数据格式,此时 body 的格式就类似于 query string(是键值对的结构,键值对之间使用 & 分割,键与值之间使用 = 分割,用post提交表单都是此类型

- multipart/form-data
这是 form 表单提交的数据格式(需要在 from 标签上加上 enctyped=“multipart/form-data”),通常用于 HTML 提交图片或者文件

  • application/json
    此时 body 数据为 json 格式,json 格式就是源自 js 的对象的格式。用一个 { } 括住,里面有多个键值对,键值对之间使用逗号分割,键和值之间使用冒号分割
1. application/x-www-form-urlencoded

后端用Request.getParameter,默认格式

2. application/json格式发送和接收

application/json 是传递的json字符串,需要用流来接收

ajxa提交

  function jsonok(){
        var mydata = {'title':'test', 'name' :'jzk'};
        $.ajax({
            type: "post",
            url: "/webdemo/hello-servlet",
            data:  JSON.stringify(mydata),
            contentType :'application/json',
            dataType: "html",
            async:true,//设置为异步
          
            success: function(data){

                alert("ok");

            },
            error:function(XMLHttpRequest, textStatus, errorThrown){

                alert("保存失败:"+XMLHttpRequest.responseText);
            }


        });
    }

后端Serlet接收,接收的是流里的字符串

InputStreamReader reader = new InputStreamReader((ServletInputStream) request.getInputStream());
        BufferedReader br=new BufferedReader(reader);
        String line=null;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }

Request

在这里插入图片描述

3. multipart/form-data格式发送和接收

html

<form id="form2" method="post"  action="/webdemo/servlet/ServletUploadDemo" enctype="multipart/form-data">
    <input type="text" name="name"><br>
    <input type="file" name="myfile"><br>
    <input type="submit" value="上传">

</form>

我们查看Request
在这里插入图片描述
解读:

  • Content-Type: multipart/form-data
    传递格式

  • boundary
    分界线,会自动生成一个分界线,用于区分多个传递参数

  • 数据体
    数据体是以分界线隔离开,里面的内容,传递的参数有两种类型1.字符串 2、文件
    通用元素:name 字段名

如果文件,里面元素有 filename=文件名, Content-Type: text/plain是文本,image/png是图片

java Servlet接收: servlet3.0已经不需要第三方fileUpload组件了

@WebServlet("/servlet/ServletUploadDemo")
@MultipartConfig//**加上这个注解,反射该Servlet时才知道处理的是文件上传

public class ServletUploadDemo extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //普通参数还可以照常取出(@MultipartConfig不能忘)
        String name = request.getParameter("name");
        System.out.println("name"+"--"+name);
        //特殊参数用part取
        Part part = request.getPart("myfile");
        System.out.println(part);

        //获取文件名
        String contentDisposition = part.getHeader("Content-Disposition");
        System.out.println(contentDisposition);// form-data; name="myfile"; filename="jj.txt"
        int filenameIndex = contentDisposition.indexOf("filename=");
        //解析获得文件名
        String filename = contentDisposition.substring(filenameIndex+10, contentDisposition.length()-1);
        System.out.println("filename==="+filename);
        String fname=filename.split("\\.")[0];//文件名
        String gs=filename.split("\\.")[1];//文件格式
        //写入服务器
        String filepath="d:\\"+fname+"-"+ new Random().nextInt()+"." +gs;
        part.write(filepath);

  		//这句话的意思,是让浏览器用utf8来解析返回的数据
        response.setHeader("Content-type", "text/html;charset=UTF-8");
       //这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
       response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>上传成功</h1>");
        out.println("</body></html>");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

2.5.2 Response 输出

对应Servlet

 response.setContentType("输出格式"; charset=utf-8");

常见的媒体格式类型如下

  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml : XML格式
  • 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 : 二进制流数据(如常见的文件下载)
1. Content-Type: text/html

输出文本,默认格式
在这里插入图片描述

2.Content-Type:application/json

输出json数据

 //输出json
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write("{'name':'蒋增奎'}");

在这里插入图片描述

3.image/png 图片
//输出图片
        response.setCharacterEncoding("utf-8");
        response.setContentType("image/png");
        OutputStream out = response.getOutputStream();
        FileInputStream fis=new FileInputStream("d:\\2.png");
        int len=-1;
        byte[] bytes=new byte[1024];
        while((len=fis.read(bytes))!=-1){
           out.write(bytes,0,len);
        }
        fis.close();

在这里插入图片描述

4.application/octet-stream 下载
//下载
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/octet-stream");
        OutputStream out = response.getOutputStream();
        FileInputStream fis=new FileInputStream("d:\\2.png");
        int len=-1;
        byte[] bytes=new byte[1024];
        while((len=fis.read(bytes))!=-1){
           out.write(bytes,0,len);
        }
        fis.close();

在这里插入图片描述

在这里插入图片描述

2.6 HTTP缓存

对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了,这样的话 HTTP/1.1 的性能肯定肉眼可见的提升。

所以,避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段。

HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存。
强制缓存
强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。

如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存。
在这里插入图片描述
协商缓存
当我们在浏览器使用开发者工具的时候,你可能会看到过某些请求的响应码是 304,这个是告诉浏览器可以使用本地缓存的资源,通常这种通过服务端告知客户端是否可以使用缓存的方式被称为协商缓存。
注意,协商缓存这两个字段都需要配合强制缓存中 Cache-control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
服务器的缓存控制

浏览器在访问页面资源时首先会查找缓存数据,如果没有再发送请求,向服务器获取资源;服务器响应请求,返回资源,同时标记资源的有效期;浏览器缓存资源,等待下次重用。这就是客户端缓存。

服务器标记资源有效期使用的头字段是Cache-Control,里面的值max-age=xxx就是资源的有效时间(与cookie的max-age不同,这里的max-age时间的计算起点是响应报文的创建时刻)。

此外在响应报文里还可以用其他的值来更精确地指示浏览器应该如何使用缓存:no-store: 不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;no-cache: 可以缓存,但在使用之前必须要去服务器验证是否过期;must-revalidate: 如果缓存不过期就可以继续使用,但过期了就必须去服务器验证。

客户端的缓存控制

浏览器也可以发Cache-Control,也就是说请求 - 应答的双方都可以用这个字段进行缓存控制,互相协商缓存的使用策略。在浏览器前进、后退、重定向时cache-control就生效了,响应头里有from disk cache字样,就说明浏览器未发送请求,而是直接使用了本地缓存。

条件请求

浏览器在刷新页面时相当于在请求头中添加了Cache-Control:no-cache,这样在刷新页面时,还是向服务端发送了请求,并没有很好的利用到缓存。所以HTTP协议又定义了一系列“If”开头的“条件请求”字段,专门用来检查验证资源是否过期。

条件请求一共有 5 个头字段,我们最常用的是if-Modified-Since和If-None-Match这两个。需要第一次的响应报文预先提供Last-modified(最后修改时间)和ETag(资源唯一标识),然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。如果资源没有变,服务器就回应一个“304 Not Modified”,表示缓存依然有效,浏览器就可以更新一下有效期,然后放心大胆地使用缓存了。

代理缓存

代理服务器

代理服务器就是客户端和服务端之间的中间商,在中间的位置转发上游的请求和下游的响应。代理服务器在计算机领域有非常重要的功能

负载均衡:面向客户端时屏蔽原服务器,代理服务器可以通过轮询、哈希等算法将流量分发,提高整体的性能。
健康检查:使用‘心跳’等机制监控服务器,保证服务器的可用性。
安全防护:保护被代理服务端的IP和流量,防止网络攻击或负载问题。
加密卸载:对外和对内使用不同的加密策略,节省加密成本
内容缓存:暂存/复位服务器的响应。
缓存代理

HTTP的服务端缓存主要由代理服务器来实现,代理服务器收到源服务器的响应之后将报文转发给客户端的同时也存入自己的cache里,下次再有相同的请求就可以直接发送304或者缓存数据,节省源服务器的成本。

因为代理服务器既是服务端,又是客户端的特性,有一些特殊的cache-control属性:

服务端
private: 表示只能客户端缓存,不允许代理服务器上缓存。punlic:表示完全公开,客户端和代理服务器都可以缓存。proxy-revalidate:要求代理服务器缓存过期后必须回源验证。s-maxage: 代理服务器缓存的有效期no-transform: 不允许代理服务器转换数据格式。

客户端
max-stale: 如果代理上的缓存过期了也可以接受,但不能过期太多,超过 x 秒也会不要。min-flash: 表示缓存少于x有效期就不要了。only-if-cached:表示只接受代理缓存的数据,不接受源服务器的响应。如果代理上没有缓存或者缓存过期,就应该给客户端返回一个 504。

2.7 cookie与session

HTTP 是“无状态”的,这既是优点也是缺点。优点是服务器没有状态差异,可以很容易地组成集群,而缺点就是无法支持需要记录状态的事务操作。好在 HTTP 协议是可扩展的,后来发明的 Cookie 技术,给 HTTP 增加了“记忆能力”。
cookie同样存在于HTTP头部字段里。服务端可以使用set-cookie标识客户端身份,客户端则在请求时携带cookie告诉服务端自己的信息。cookie字段以key=value的格式保存,浏览器在一个cookie字段里可以存放多对数据,用;分割。

在这里插入图片描述
Cookie 主要用于以下三个方面:

会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
个性化设置(如用户自定义设置、主题等)
浏览器行为跟踪(如跟踪分析用户行为等)

  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值