Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象、和代表响应的response对象。

既然request对象代表http请求,那么我们获取浏览器提交过来的数据,找request对象即可。response对象代表http响应,那么我们向浏览器输出数据,找response对象即可。

http响应由状态行、实体内容、消息头、一个空行组成。一个HTTP响应代表着服务器向浏览器回送数据,HttpServletResponse对象就封装了http响应的信息。

一个完整http请求应该包含三个部分:

  1. 请求行【描述客户端的请求方式请求的资源名称,以及使用的HTTP协议版本号

  2. 多个消息头【描述客户端请求哪台主机,以及客户端的一些环境信息等】

  3. 一个空行

请求行

请求行:GET /java.html HTTP/1.1

请求行中的GET称之为请求方式,请求方式有:POST,GET,HEAD,OPTIONS,DELETE,TRACE,PUT。

请求头

  • Accept: text/html,image/* 【浏览器告诉服务器,它支持的数据类型】

  • Accept-Charset: ISO-8859-1 【浏览器告诉服务器,它支持哪种字符集

  • Accept-Encoding: gzip,compress 【浏览器告诉服务器,它支持的压缩格式

  • Accept-Language: en-us,zh-cn 【浏览器告诉服务器,它的语言环境】

  • Host: www.it315.org:80【浏览器告诉服务器,它的想访问哪台主机】

  • If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT【浏览器告诉服务器,缓存数据的时间】

  • Referer: http://www.it315.org/index.jsp【浏览器告诉服务器,客户机是从那个页面来的---反盗链

  • 8.User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)【浏览器告诉服务器,浏览器的内核是什么】

  • Cookie【浏览器告诉服务器,带来的Cookie是什么

  • Connection: close/Keep-Alive 【浏览器告诉服务器,请求完后是断开链接还是保持链接】

  • Date: Tue, 11 Jul 2000 18:23:51 GMT【浏览器告诉服务器,请求的时间】

一个完整的HTTP响应应该包含四个部分:

  1. 一个状态行【用于描述服务器对请求的处理结果。

  2. 多个消息头【用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据

  3. 一个空行

  4. 实体内容【服务器向客户端回送的数据

状态行

格式: HTTP版本号 状态码 原因叙述

状态行:HTTP/1.1 200 OK

状态码用于表示服务器对请求的处理结果,它是一个三位的十进制数。响应状态码分为5类。

响应头

  • Location: http://www.it315.org/index.jsp 【服务器告诉浏览器要跳转到哪个页面

  • Server:apache tomcat【服务器告诉浏览器,服务器的型号是什么】

  • Content-Encoding: gzip 【服务器告诉浏览器数据压缩的格式

  • Content-Length: 80 【服务器告诉浏览器回送数据的长度】

  • Content-Language: zh-cn 【服务器告诉浏览器,服务器的语言环境】

  • Content-Type: text/html; charset=GB2312 【服务器告诉浏览器,回送数据的类型

  • Last-Modified: Tue, 11 Jul 2000 18:23:51 GMT【服务器告诉浏览器该资源上次更新时间】

  • Refresh: 1;url=http://www.it315.org【服务器告诉浏览器要定时刷新

  • Content-Disposition: attachment; filename=aaa.zip【服务器告诉浏览器以下载方式打开数据

  • Transfer-Encoding: chunked 【服务器告诉浏览器数据以分块方式回送】

  • Set-Cookie:SS=Q0=5Lb_nQ; path=/search【服务器告诉浏览器要保存Cookie

  • Expires: -1【服务器告诉浏览器不要设置缓存

  • Cache-Control: no-cache 【服务器告诉浏览器不要设置缓存

  • Pragma: no-cache 【服务器告诉浏览器不要设置缓存

  • Connection: close/Keep-Alive 【服务器告诉浏览器连接方式】

  • Date: Tue, 11 Jul 2000 18:23:51 GMT【服务器告诉浏览器回送数据的时间】

response调用getOutputStream()方法向浏览器输出数据,getOutputStream()方法可以使用print()也可以使用write()它们有什么区别呢

  • 为什么会出现异常呢?在io中我们学过,outputStream是输出二进制数据的print()方法接收了一个字符串print()方法要把“中国”改成二进制数据,Tomcat使用IOS 8859-1编码对其进行转换,“中国”根本对ISO 8859-1编码不支持。所以出现了异常

  • 我们再看看write()方法

        response.getOutputStream().write("aaa".getBytes());//正常显示

      response.getOutputStream().write("你好呀我是中国".getBytes());//正常显示
  • 为什么使用write()方法能够正常向浏览器输出中文呢?"你好呀我是中国".getBytes()这句代码在转成byte[]数组的时候使用平台默认字符集(某中文编码),而浏览器正好编码字符集也是某中文编码,所以中文可以正常显示出来。

  • 但是,程序要实现通用性,应该使用的是UTF-8编码,我们在字符串转换成字节数组时指定UTF-8编码,看看会怎么样。

     response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));//乱码了,乱不乱码是跟每个电脑的字符集息息相关的,不同电脑,可能显示结果不一样。
  • 为什么它变成了乱码呢?原因是这样的:我在向服务器输出的中文是UTF-8编码的,而浏览器采用的是GBK,GBK想显示UTF-8的中文数据,不乱码才怪呢

  • 既然如此,我将浏览器的编码改成UTF-8试试。
  • 乱码问题又解决了。可是,每次编写UTF-8程序时都要去网页上改编码格式吗?这样明显不可能的
  • 既然HTTP响应有对浏览器说明回送数据是什么类型的消息头,那么HttpServletResponse对象就应该有相对应的方法告诉浏览器回送的数据编码格式是什么
  • 于是乎就去查找Servlet API,找到了设置消息头的方法
  •         //设置头信息,告诉浏览器我回送的数据编码是utf-8的,浏览器会自动拿utf-8解码
           response.setHeader("Content-Type", "text/html;charset=UTF-8");
           response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));
  • 浏览器在显示数据时,自动把页面的编码格式置换成UTF-8,乱码问题也解决了
  • 另外,除了使用HttpServletResponse对象设置消息头的方法,我可以使用html的标签模拟一个http消息头
  • 下面是代码:
  • //获取到servletOutputStream对象
  • ServletOutputStream servletOutputStream = response.getOutputStream();
    //使用meta标签模拟http消息头,告诉浏览器回送数据的编码和格式
    servletOutputStream.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes());
    servletOutputStream.write("我是中国".getBytes("UTF-8"));
  • 对于getWriter()方法而言,是Writer的子类,那么只能向浏览器输出字符数据,不能输出二进制数据

  • 使用getWriter()方法输出中文数据,代码如下:

        //获取到printWriter对象
       PrintWriter printWriter = response.getWriter();
       printWriter.write("看完博客点赞!");;//乱码了
  • 为什么出现乱码了呢?由于Tomcat是外国人的写,Tomcat默认的编码是ISO 8859-1即(response.getCharacterEncoding()是iso-8859-1),当我们输出中文数据的时候,Tomcat会依据ISO 8859-1码表给我们的数据编码,中文不支持这个码表呀,所以出现了乱码(不识别的话就显示问号)

  • 既然如此,我设置一下编码不就好了吗,代码如下:

        //原本是ISO 8859-1的编码,我设置成UTF-8
       response.setCharacterEncoding("UTF-8");        //获取到printWriter对象
       PrintWriter printWriter = response.getWriter();
       printWriter.write("看完博客点赞!");//乱码了
  • 为什么乱码问题还没有解决?细心的朋友会发现,我只是在中文转换的时候把码表设置成UTF-8,但是浏览器未必是使用UTF-8码表来显示数据的呀

  • 好的,我们来看看浏览器的编码格式,果然,浏览器使用GB2312显示UTF-8的数据,不乱码才怪呢

  • 这个问题我们在上面已经是有两种方法解决了【使用标签模拟消息头、设置消息头】,Servlet还提供了一个方法给我们

        //设置浏览器用UTF-8编码显示数据
       response.setContentType("text/html;charset=UTF-8");
  • 既然Servlet有那么多方法解决乱码问题,是不是有一种是最简便的呢?没错!下面这个方法是最简便的,它不仅设置浏览器用UTF-8显示数据,内部还把中文转码的码表设置成UTF-8了,也就是说response.setContentType("text/html;charset=UTF-8");response.setCharacterEncoding("UTF-8")的事情也干了!

  • 使用getWriter()显示中文数据,只需要一个方法就搞掂了!

        //设置浏览器用UTF-8编码显示数据,
       response.setContentType("text/html;charset=UTF-8");        //获取到printWriter对象
       PrintWriter printWriter = response.getWriter();
       printWriter.write("看完博客点赞!");
response应用2-实现文件下载

既然浏览器发送所有的请求都是去找Servlet的话,那么我就写一个Servlet,当别人访问我这个Servlet的时候,它们就可以下载我这个图片了。

  • java的文件上传下载都是通过io流来完成的,既然要下载图片,首先要能够读取到它

      //获取到资源的路径
String path = this.getServletContext().getRealPath("/download/1.png"); //读取资源
FileInputStream fileInputStream = new FileInputStream(path); //获取到文件名,路径在电脑上保存是\\形式的。
String fileName = path.substring(path.lastIndexOf("\\") + 1);
  • 告诉浏览器,我要下载这个文件

   //设置消息头,告诉浏览器,我要下载1.png这个图片
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
  • 将读取到的内容回送给浏览器

        //把读取到的资源写给浏览器
int len = 0;
byte[] bytes = new byte[1024];
ServletOutputStream servletOutputStream = response.getOutputStream(); while ((len = fileInputStream.read(bytes)) > 0) {
servletOutputStream.write(bytes, 0, len);
} //关闭资源
servletOutputStream.close();
fileInputStream.close();

  • 为了解决文件名乱码,我们要进行URL编码,代码如下:


  response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

应用3-实现自动刷新


以规定的时间让页面刷新,更新资源
让浏览器实现自动刷新,那肯定又是修改消息头了。

  //每3秒自动刷新网页一次
response.setHeader("Refresh", "3");
为了更好的看效果,我们加入时间值进去

   response.getWriter().write("time is :" + System.currentTimeMillis());
我们登陆完网站,很多时候都会看见【登陆成功,3秒后自动跳转….】,其实这个就是用Refresh来完成的。

        response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("3秒后跳转页面....."); //三秒后跳转到index.jsp页面去,web应用的映射路径我设置成/,url没有写上应用名
response.setHeader("Refresh", "3;url='/index.jsp'");

应用4-设置缓存

浏览器本身就存在着缓存机制,当我第一次访问index.jsp时,浏览器向服务器发了两次请求【一个是网页的,一个是图片的】

当我第二次访问index.jsp的时候,浏览器将图片缓存起来了!图片不是重新加载的,是从缓存里面取出来的

像股票类型的网页是不能取缓存的数据的,数据都是要不断更新的。下面我就禁止缓存的功能


        //浏览器有三消息头设置缓存,为了兼容性!将三个消息头都设置了
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma", "no-cache"); //这里为了看效果
PrintWriter printWriter = response.getWriter();
printWriter.print("你好啊" + new Date().toString());

如果页面有些数据不长期更新,你就将它设置成缓存,这样可以提高服务器的性能

应用5-实现数据压缩

网页上的信息量是很大的,如果不将数据压缩再回送给浏览器,这样就十分耗费流量

        response.setContentType("text/html;charset=UTF-8");

        String ss = "fsdfhsdfhuisdhfusdhfuids" +
"fsdfdsfsdfsdfdsfdafdsfhsdjfhsdjkfhkjds" +
"fdsfjdslkfjsldkfjsdlkfjsdkfsdjkff" +
"fsjdfjdsklfjdsklfjkldsfjlksdjflksdjflkds" +
"dsjfklsdjflsdjfkldsfkjsdkfjsldkfjsdlfk" +
"fdsjlkfjdslkfjsdlkfjlkasjflk";
response.getWriter().write("原来的长度是:"+ss.getBytes().length+"</br>"); //输出给浏览器
response.getWriter().write(ss);
  • 压缩的原理是什么?我们知道getOutputStream()和getWriter()都是直接把数据输出给浏览器的。现在我要做的就是让数据不直接输出给浏览器,先让我压缩了,再输出给浏览器java提供了GZIP压缩类给我们

  • 就让我们使用GZIP类来对数据压缩吧


 //GZIP的构造方法需要一个OutputStream子类对象,究竟哪个对象适合,我们看下write()方法
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(); //查看了下API,write()接收的是byte[]类型的。
gzipOutputStream.write();
  • 于是我就在构造函数上传递个ByteArrayOutputStream给它

    //既然是byte[]类型,那么我就给他一个ByteArrayOutputStream
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new ByteArrayOutputStream());
  • 而用GZIPOutputStream写数据的时候,是把数据写到ByteArrayOutputStream上的,等会还要把数据取出来,再写给浏览器,于是就不能以匿名内部类的方式给GZIPOutputStream,必须把ByteArrayOutputStream定义出来

  •   //创建GZIPOutputStream对象,给予它ByteArrayOutputStream
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream); //GZIP对数据压缩,GZIP写入的数据是保存在byteArrayOutputStream上的
    gzipOutputStream.write(ss.getBytes()); //gzipOutputStream有缓冲,把缓冲清了,并顺便关闭流
    gzipOutputStream.close();

  把压缩后的数据取出来,写给浏览器

          //将压缩的数据取出来
byte[] bytes = byteArrayOutputStream.toByteArray(); //将压缩的数据写给浏览器
response.getOutputStream().write(bytes);//浏览器显示乱码
  • 数据的确是压缩了,然而,为什么又乱码了啊?很简单,既然你压缩了数据,你写给浏览器,浏览器是不知道你这是压缩后的数据,它是以正常的方式打开数据的。这当然造成乱码啦!,现在我要告诉浏览器我这是压缩数据

  //告诉浏览器这是gzip压缩的数据
response.setHeader("Content-Encoding","gzip"); //再将压缩的数据写给浏览器
response.getOutputStream().write(bytes);

应用6-生成随机图片

生成随机图片这是非常常见的。在我们登陆的时候经常要写验证码,而那些验证码是一张图片,就是通过HttpServletResponse写给浏览器的。

  • 要生成一张图片,java提供了BufferedImage类供我们使用

        //在内存中生成一张图片,宽为80,高为20,类型是RGB
BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB); //获取到这张图片
Graphics graphics = bufferedImage.getGraphics(); //往图片设置颜色和字体
graphics.setColor(Color.BLUE);
graphics.setFont(new Font(null, Font.BOLD, 20)); //往图片上写数据,先写个12345,横坐标是0,纵坐标是20【高度】
graphics.drawString("12345", 0, 20);
  • 好的,现在我们在内存中创建了一张图片,并写上了12345。接着,我们要把图片写给浏览器了把图片写给浏览器,java又提供了图片流【ImageIO】给我们使用

   //要往浏览器写一张图片,那要告诉浏览器回送的类型是一张图片
response.setHeader("ContentType", "jpeg"); //java提供了图片流给我们使用,这是一个工具类
//把图片传进去,类型是jpg,写给浏览器
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
  • 好的,我们的图片数字不可能是人工写的,数字应该是随机产生的!这个就简单了。现在我要生成7位的随机数,生成随机数的方法如下


  private String makeNum() {

        Random random = new Random();

        //这样就会生成0-7位的随机数,现在问题又来了,如果随机数不够7位呢?如果不够7位,我们加到7位就行了
int anInt = random.nextInt(9999999); //将数字转成是字符串
String num = String.valueOf(anInt); //判断位数有多少个,不够就加
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 7 - num.length(); i++) {
stringBuffer.append("0");
} return stringBuffer.append(num).toString(); }

应用7-重定向跳转

什么是重定向跳转呢?点击一个超链接,通知浏览器跳转到另外的一个页面就叫重定向跳转。是通知浏览器去跳转,这很重要。页面之间的跳转有两种方式:重定向和转发,至于什么时候用重定向,什么用转发,我在讲完HttpServletRequest对象的时候会详细说明。


//重定向到index.jsp页面
response.sendRedirect("/zhongfucheng/index.jsp");

重定向是通过302状态码和跳转地址实现的。于是乎,我们设置http消息头就可以实现重定向跳转


        //设置状态码是302
response.setStatus(302); //HttpServletResponse把常用的状态码封装成静态常量了,所以我们可以使用SC_MOVED_TEMPORARILY代表着302
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); //跳转的地址是index.jsp页面
response.setHeader("Location", "/zhongfucheng/index.jsp");

  • 其实sendRedirect()方法就是对setStatus()和setHeader()进行封装,原理就是setStatus()和setHeader()

  最后再说下getWriter和getOutputStream细节
  1. getWriter()和getOutputStream()两个方法不能同时调用。如果同时调用就会出现异常

  2. Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端

  3. Servlet的serice()方法结束后【也就是doPost()或者doGet()结束后】,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象.

 

request和response简介的更多相关文章

  1. Servlet第三篇【request和response简介、response的常见应用】

    response.request对象 Tomcat收到客户端的http请求,会针对每一次请求,分别创建一个代表请求的request对象.和代表响应的response对象 既然request对象代表ht ...

  2. JavaWeb(一)Servlet中的request与response

    一.HttpServletRequest概述 1.1.HttpServletRequest简介 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP ...

  3. Request和Response

    1 简介 web服务器收到客户端的http请求,会针对每一个请求,分别创建一个用于代表请求的request对象和代表响应的response对象. request和response对象既然代表请求和响应 ...

  4. 第十五节:HttpContext五大核心对象的使用(Request、Response、Application、Server、Session)

    一. 基本认识 1. 简介:HttpContext用于保持单个用户.单个请求的数据,并且数据只在该请求期间保持: 也可以用于保持需要在不同的HttpModules和HttpHandlers之间传递的值 ...

  5. Fiddler抓包4-工具介绍(request和response)

    前言 本篇简单的介绍下fiddler界面的几块区域,以及各自区域到底是干什么用的,以便于各好的掌握这个工具 一.工具简介 1.第一块区域是设置菜单,这个前面2篇都有介绍 2.第二块区域是一些快捷菜单, ...

  6. JSP 中的 Request 和 Response 对象

    客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应.它是HttpServletRequest类的实例:response对象包含了响应客户请求的有关信息,但在JSP中 ...

  7. JavaWeb Request和Response

    1. Request与Response 1.1. Web应用运行机制 到目前为止,我们已经掌握了Web应用程序的运行机制,现在学习的就是Web应用程序运行机制中很重要的内容 —— Request与Re ...

  8. Fiddler抓包4-工具介绍(request和response)【转载】

    本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/p/6719717.html 前言 本篇简单的介绍下fiddler界面的几块区域,以及各自区域到 ...

  9. Fiddler抓包-工具介绍(request和response)

    from:https://www.cnblogs.com/yoyoketang/p/6731121.html 本篇简单的介绍下fiddler界面的几块区域,以及各自区域到底是干什么用的,以便于各好的掌 ...

随机推荐

  1. mysql_day04

    MySQL-Day03回顾1.索引 1.普通索引 index 2.唯一索引(UNI,字段值不允许重复,但可以为NULL) 1.创建 1.字段名 数据类型 unique 2.unique(字段名), u ...

  2. SSM框架整合过程总结

    -----------------------siwuxie095                                 SSM 框架整合过程总结         1.导入相关 jar 包( ...

  3. JAVA中float与double的区别

    float是单精度类型,精度是8位有效数字,取值范围是10的-38次方到10的38次方,float占用4个字节的存储空间 double是双精度类型,精度是17位有效数字,取值范围是10的-308次方到 ...

  4. [leetcode]78. Subsets数组子集

    Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solut ...

  5. SpringMVC 使用验证框架 Bean Validation(上)

    SpringMVC 使用验证框架 Bean Validation(上) 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. ...

  6. 本机连接Spark Standalone--最简单的spark调试方式

    为了既能远程连接spark  查看ui  又能本地练习  安装简单 去官网  http://spark.apache.org/downloads.html  选择对应版本下载 tar包 解压 tar ...

  7. Python开发——函数【装饰器、高阶函数、函数嵌套、闭包】

    装饰器 装饰器本质就是函数,为其他函数添加附加功能. 原则: 不修改被修饰函数的源代码 不修改被修饰函数的调用方法 装饰器知识储备:装饰器 = 高阶函数 + 函数嵌套 + 闭包 案例:求函数运行时间! ...

  8. vi/vim 文字处理器常用命令

    目录 vi 与vim vi 的三种模式 vi 光标移动 vi 搜索与替换 vi 删除 vi 复制 vi 粘贴 vi 其他 vi 进入编辑模式 vi 命令行命令 vim 附加功能 vi 与vim vi是 ...

  9. docker容器的使用

    Docker客户端 docker客户端非常简单,我们可以直接输入docker命令来查看到Docker客户端的所有命令选项. runoob@ docker 可以通过命令docker command -- ...

  10. 创建.NET core的守护进程

    http://www.cnblogs.com/savorboard/p/dotnetcore-supervisor.html