Response对象

Response对象

封装了所有响应信息并将服务器端资源数据输出到浏览器

HttpServletResponse 对象封装了向客户端发送数据、发送响应头,发送响应状态码的
方法。
1.封装了所有响应数据(获取不到,但是可以设置响应头数据,如果你不设置都会有默认值)

2.页面跳转—重定向

3.响应头作用
a)数据压缩
b)附件下载
c)验证码

响应数据格式

响应行,响应头,响应体.

响应行(状态行)

响应行的组成
 响应行是http响应内容的第一行。

 响应行一般数据为:HTTP/1.1 200(tomcat8.5) 或者 HTTP/1.1 200 OK(tomcat7)

 响应行分为三个部分:
        HTTP/1.1:协议版本
        200:响应状态码
        OK:对响应状态码的解释

常见的响应状态码:

1.200 OK  请求已成功,服务器通信正常。

2.302 Move temporarily 设置重定向页面跳转的动作执行。

3.304 Not Modified  从浏览器缓存中读取数据,不从服务器重新获取数据。

4.403 Forbidden  服务器已经理解请求,但是拒绝执行它。由于资源没有执行权限,导致无法执行.

5.404 Not Found  请求失败,请求所希望得到的资源未被在服务器上发现。一般是用户输错了url导致.

6.405 Method Not Allowed  请求行中指定的请求方法不存在。
例如,发送post请求,服务器没有doPost方法,就会报这个错误.

7.500 Internal Server Error  服务器发生了错误。一般服务器代码错误

//设置http响应状态码
response.setStatus(302);

响应头作用

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   --下载
Set-Cookie:SS=Q0=5Lb_nQ; path=/search
Expires: -1                 --缓存
Cache-Control: no-cache             --缓存
Pragma: no-cache                --缓存
Connection: close/Keep-Alive            --连接
Date: Tue, 11 Jul 2000 18:23:51 GMT     --时间

常见的响应头介绍

1. location:
重定向操作:通知浏览器马上向该地址发送请求,通常和响应码 302 一起使用。

2. content-encoding:
设置当前数据的压缩格式,通知浏览器以何种压缩格式解压数据。
比如像浏览器输出一个压缩文件,可以设置这个响应头通知浏览器解压显示数据,
但是目前浏览器只支持”gzip”格式解压

3.refresh:
定时刷新跳转页面

4. content-disposition:
通知浏览器以何种方式获取数据(直接解析数据(网页,图片文本),或者以附件方式(下载文件))


5. content-type
实体头部用于指示资源的 MIME 类型(MIME 类型:用于提示当前文件的媒体类型,)
例如:
图片——(image/png)
音频——(audio/ogg)。
它的作用与传统上 windows 上的文件扩展名相同。


我们 content-type 一般都设置为”text/html;charset=utf-8”,

其中"text/html";——设置浏览器以文本格式解析数据;
"charset=utf-8"——响应数据的编码表。

response常用API

void setHeader(String name, String value)  用给定名称和值设置响应头
//通知浏览器进行页面跳转到index.html页面
response.setHeader("location", "/demo/index.html");

void setStatus(int sc) 设置此响应的状态代码
//设置http响应状态码
response.setStatus(302);

页面跳转—重定向

//响应头---Location
//作用,通知浏览器进行页面跳转

//设置响应头的数据//设置消息头
//response.setHeader(name, value);

//通知浏览器进行页面跳转到index.html页面
response.setHeader("location", "/demo/index.html");

//如果想使用响应头location进行页面跳转必须配合设置http状态码302
//302,进行页面跳转重定向的
//location和302一起使用最终实现页面跳转重定性

//设置http响应状态码
response.setStatus(302);
//以上代码使用如下代码替代
response.sendRedirect("/demo/index.html");//实现原理就是上面2句代码

页面转发与重定向区别

1.请求转发url没有发生变化,//重定向url发生变化

2.请求转发跳转发生在服务器内部,重定向跳转发生在浏览器客户端

3.请求转发是服务器内部跳转,只能访问当前资源目录里面的资源;

重定向是客户端浏览器发生跳转,所以可以访问本服务器上任意位置资源


4.请求转发共享一个request和response,重定向不共享。

5.请求转发访问的是同一目录下的资源,所以访问速度快 ;

重定向可以访问本服务器上的任意位置资源,所以访问速度比较慢.
//使用 response 响应对象设置响应头
//服务器通知浏览器 3 秒后,刷新,并让浏览器访问 www.baidu.com
//参数一:响应头
//参数二:响应头对应的值
//3 表示秒数,后边有一个分号,url=后面写浏览器访问的路径
response.setHeader("refresh","3;url=http://www.baidu.com");
//设置一个响应状态码
response.setStatus(200);
//服务器通知浏览器重定向到/work/login.html 页面
//response.setHeader("location","http://127.0.0.1:8080/work/login.html");
//response.setStatus(302);
//以上请求重定向的简写形式,我们很常用


//参数一:请求重定向的地址,可以 html/jsp/servlet
//请求重定向中这个地址中/表示 Tomcat 中的 webapps 目录,浏览器参与
//请求转发中这个地址中/表示 Tomcat 中的 work 目录,是服务器内部的事情,浏览器不参与
//response.sendRedirect("/work/login.html");
//response.sendRedirect(request.getContextPath()+"/login.html");

//请求重定向到 XxxServlet
response.sendRedirect(request.getContextPath()+"/ResponseServlet");

解决服务器输出字符流中文乱码

//在获取输出流之前,设置输出的类型和字符集
//有三层含义:
//1:服务器采用 UTF-8 编码(UTF-8 大小写不敏感)
//修改response默认输出中文数据码表
//response.setCharacterEncoding("utf-8");
//2:通知浏览器接收的类型是 text/html 类型
//3:通知浏览器采用 UTF-8 解码
//response.setHeader("content-type","text/html;charset=UTF-8");
//上述代码简写
response.setContentType("text/html;charset=UTF-8");

//从 response 对象中获取,字节输出流
//OutputStream os = response.getOutputStream();
//从 response 对象中获取,字符输出流
PrintWriter writer = response.getWriter();

//输出内容
writer.write("<ul>");
writer.write("<li>北京</li>");
writer.write("<li>上海</li>");
writer.write("<li>广州</li>");
writer.write("</ul>");

//刷新并关闭字符输出流
writer.flush();
writer.close();

//总结:
//请求乱码:doPost()获取请求数据之前,调用 
request.setCharacterEncoding("UTF-8");

//响应乱码:doPost()/doGet()获取字符/节输出流之前,调用
response.setCharacterEncoding("utf-8");
response.setHeader("content-type","text/html;charset=UTF-8");
或
response.setContentType("text/html;charset=UTF-8");

定时刷新

Refresh: 1;url=http://www.it315.org     --定时刷新

描述:1秒以后页面跳转到http://www.it315.org
/*需求:3秒以后跳转到demo.html*/
response.setHeader("refresh","3;url="+getServletContext().getContextPath()+"/demo.html");
页面倒计时进行跳转到某一资源页面
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
    //定义倒计时数字
    var count = 3;
    //当页面加载完成时调用
    window.onload=function(){
        //倒计时
        tick();
    }
    //启动倒计时
    function tick(){
        //判断倒计时数字大于0继续进行倒计时操作
        if(count>0){
            //获得页面中显示倒计时的标签对象
            var p = document.getElementById("one");
            //页面显示倒计时数字,显示后数字减1
            p.innerHTML=count--;
            //设置定时在一秒后继续调用当前方法
            window.setTimeout(tick, 1000);
        }
    }
</script>
</head>
<body>
页面在<p id="one">3</p>秒后跳转...
</body>
</html>
//要求2:页面倒计时3秒之后跳转到demo.html
//分析:第一次跳转到倒计时页面,第二次3秒以后跳转到demo.html
response.setHeader("refresh", "3;url="+getServletContext().getContextPath()+"/demo.html");

//直接跳转倒计时页面wait.html(页面跳转必须时候转发)
request.getRequestDispatcher("/wait.html").forward(request, response);

Content-Encoding 数据压缩

public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    //需求:向客户端输出大文本数据,4000个字符

    //问题:数据是被压缩了,但是浏览器不能直接看数据了,而是下载了一个压缩包文件。
    //通知浏览器解压数据后再显示数据
    response.setHeader("content-encoding", "gzip");

    //获取字符流
    //PrintWriter out = response.getWriter();
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 0; i < 1000; i++) {
        //out.write("abcd");
        stringBuilder.append("abcd");
    }

    //如果传输数据量比较大,可以进行数据压缩
    //通过数据压缩流压缩数据就可以了
    //GZIPOutputStream 是一个压缩流,但是不具备输出的功能,
    //所以需要借助response.getOutputStream()输出数据
    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(response.getOutputStream()); 

    //压缩数据,将压缩的数据放到内存中去了
    gzipOutputStream.write(stringBuilder.toString().getBytes());

    //将内存中的压缩数据给到response输出
    gzipOutputStream.finish();

    //已经将压缩的数据发送给浏览器客户端了

}

以附件形式下载文件

Content-Disposition: attachment; filename=aaa.zip   --下载
attachment,通知浏览器不要显示数据要以附件形式下载
filename=aaa.zip,下载的文件名字

通知浏览器不要直接显示数据,以附件形式下载数据。
默认浏览器查看数据是直接显示数据,有的资源下载网站需要下载资源数据而不是直接显示,
所以需要通过设置响应头content-disposition来通知浏览器以附件下载数据。
* 响应头:content-disposition
*    格式:attachment; filename=aaa.zip
*    作用,通知浏览器以附件下载方式下载文件
* */
//要求:通知浏览器下载这个图片
//response.setHeader("content-disposition","attachment;filename=2.jpg");
1. 创建一个页面,展示所有要被下载文件的链接。

2. 链接将要下载的文件名称,发送给服务器的 Servlet,
让 Servlet 进行处理服务器加载文件资源。
//浏览器中:
//get的方式传递中文IE 浏览器不进行URL 编码,其他浏览器都进行URL 编码。
//所以IE 浏览器,传递中文得先进行 URL 编码后,才能传递到服务器
<script>
    //判断是否为 IE,如果是 IE,返回 true,否则返回 false
    function isIE(){
    //获取当前浏览器相关信息
    var userAgent = window.navigator.userAgent.toLocaleLowerCase();
    var ie10 = userAgent.indexOf("msie") > 0 ? true : false;;
    var ie11 = userAgent.indexOf("rv:11.0") > 0 ? true : false;
    var edge = userAgent.indexOf("edge") > 0 ? true : false;;

    //判断是否是 ie 浏览器
    if (ie10 || ie11 || edge) {
            return true;
        }else {
            return false;
        }
    }

    window.onload = function(){
        //如果是 IE 浏览器,中文得进行 URL 编码后,才能传递到服务器
        if(isIE()){
        var a = document.getElementById("xx");
        var href = a.href;
        var encodeHref = encodeURI(href);
        a.href = encodeHref;
        }
    }
</script>
//服务器中:
//服务器与浏览器传输数据默认只会对请求行,请求体,响应行,响应体进行URL编码的操作,
//不会对请求头与响应头进行URL编码操作
//所以需要我们自己手动对响应头中文数据进行URL编码操作

//处理中文文件名乱码问题
//如果是 IE 的话,进行 UTF-8 编码
//如果是非 IE 的话,先按 UTF-8 解码,再按 ISO8859-1 编码


//1 获取要下载的文件名称
String fileName = request.getParameter("fileName");
System.out.println(fileName);

//2 加载当前文件
// 注意:需要动态的获取当前文件的目录位置(即使服务器所在目录发生变化,我也可以获取到准确位置)
// 我们需要使用servletContext,获取资源路径
ServletContext context = getServletContext();
String realPath = context.getRealPath("/download");
File file = new File(realPath,fileName);

//3 提示浏览器,以下载的方式,获取服务器资源
//响应消息头设置:
//Content-Type 设置文件媒体格式   getMimeType:1.txt  2.jpg  获取文件的后缀名
response.setContentType(getServletContext().getMimeType(fileName));

// 获取浏览器类型,通过请求头中的User-Agent来判断
String ua = request.getHeader("User-Agent");
boolean IE_LT11 = ua.contains("MSIE"); // IE11以下版本
boolean IE11 = ua.contains("rv:11.0) like Gecko"); // IE11
boolean Edge = ua.contains("Edge"); // win10自带的Edge浏览器

// 如果是微软的浏览器,直接进行UTF-8编码
if (IE_LT11 || IE11 || Edge) {
    fileName = URLEncoder.encode(fileName, "UTF-8");
    // java的编码方式和浏览器有略微的不同:对于空格,java编码后的结果是加号,
    // 而浏览器的编码结果是%20,因此将+替换成%20, 这样浏览器才能正确解析空格
    fileName = fileName.replace("+", "%20");
}

// 标准浏览器使用Base64编码
else {
    Base64.Encoder encoder = Base64.getEncoder();
    fileName = encoder.encodeToString(fileName.getBytes("utf-8"));
    // =?utf-8?B?文件名?= 是告诉浏览器以Base64进行解码
    fileName = "=?utf-8?B?" + fileName + "?=";
}
//Content-Disposition  设置要被下载的文件名
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

响应体

就是服务器输出数据给用户看,浏览器直接要显示给用户的网页数据,就是服务器输出数据
1.输出字符数据、字节数据
2.输出资源文件数据(资源图片)
3.输出缓存(内存中)图片(资源没有对应的物理资源)--验证码

验证码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="LoginServlet" method="post">
    <table>
        <tr>
            <td>用户名</td>
            <td><input type="text" name="username"/></td>
        </tr>
        <tr>
            <td>密码</td>
            <td><input type="password" name="password"/></td>
        </tr>
        <tr>
            <td>验证码:</td>
            <td><input type="password" name="checkcode"/></td>
        </tr>
        <tr>
            <td></td>
            <td><img id="img" onclick="changeCheckCode(this)" src="CheckCodeServlet"/></td>
        </tr>
        <tr>
            <td></td>
            <td><input type="submit" value="登录"/></td>
        </tr>
    </table>
    <script type="text/javascript">
        //图片点击事件
        function changeCheckCode(imgObj) {
            imgObj.src="CheckCodeServlet?time="+new Date().getTime();
            //浏览器对于图片img,默认不会重新请求,除非src的值改变了,浏览器就会重新加载src的资源
        }

    </script>
</form>
</body>
</html>
    /*案例:输出验证码图片
    * */
    //BufferedImage,缓存图片对象
    //  构造函数new BufferedImage(width,height,imagetype);
    //          width,图片宽度
    //          height,高度
    //          imagetype,图片的模式

    BufferedImage image = new BufferedImage(90,30,BufferedImage.TYPE_INT_RGB);
    //获取画笔
    Graphics g = image.getGraphics();

    //填充区域
    g.fillRect(0,0,90,30);

    //设置画笔颜色
    g.setColor(Color.red);

    //设置边框
    g.drawRect(0,0,90-1,30-1);

    //画干扰线,防止通过软件扫描验证码识别
    //g.drawLine();

    for(int i=0;i<3;i++){

        g.setColor(getRandomColor());
        int x1=random.nextInt(89);
        int y1 =random.nextInt(29) ;
        int x2=random.nextInt(89);
        int y2 =random.nextInt(29) ;
        g.drawLine(x1,y1,x2,y2);
    }

    //画验证码
    String checkCode= "23456789qwertyupasdfghjkzxcvbnmQWERTYUPASDFGHJKLZXCVBNM";

    //画4个验证码到图片上
    StringBuilder checkCodeBuilder = new StringBuilder();
    for(int i=0;i<4;i++){
        int index = random.nextInt(checkCode.length());
        char item = checkCode.charAt(index);

        checkCodeBuilder.append(item);//以后验证验证码的时候用

        //每个字符随机颜色
        g.setColor(getRandomColor());

        //画到验证码
        g.drawString(item+"",10+(i*20),20);
    }

    //ImageIO,可以将缓存图片输出给浏览器显示
    ImageIO.write(image,"png",response.getOutputStream());
}


/**
 * 获取随机颜色
 * @return Color
 */
private Color getRandomColor(){
    int r=random.nextInt(256);
    int g=random.nextInt(256);
    int b=random.nextInt(256);

    return new Color(r,g,b);
}
response.getOutputStream().write("1".getBytes()); 
PrintWriter p = response.getWriter();
p.print("2"); 


只能回应一次请求? or一个页面只能用一个输出流?
一次响应只能使用一种类型输出流,要么字符流,要么字节流。这是服务器输出数据的机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值