服务器处理请求的流程:
(1) 服务器每次收到请求时,都会为这个请求开辟一个新的线程;
(2) 服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体;
(3) 服务器还会创建response对象,这个对象与客户端连接在一起,它可以用来向客户端发送响应。
ServletResponse:与协议无关的类型;HttpServletResponse:与http协议相关的类型。
response是Servlet#service(ServletRequest, ServletResponse) 方法的一个参数,类型为javax.servlet.ServletResponse;
在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet#service(ServletRequest, ServletResponse)方法;
response对象是用来对客户端进行响应的,这说明在service(ServletRequest, ServletResponse) 方法中使用response对象可以完成对客户端的响应工作;
接口ServletResponse的定义可参考“JSP内置对象之response对象”,“response”对象的原型即实现了此接口。
响应首行;响应头(头名-头值);空行;响应体。
响应内容是由服务器发送给浏览器的内容,浏览器会根据响应内容来显示。
Status-Line) HTTP/1.1 200 OK
Server Apache-Coyote/1.1
Content-Type text/html;charset=UTF-8
Content-Length 740
Date Mon, 12 Jan 2015 12:46:23 GMT
l 200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
l 404:请求的资源没有找到,说明客户端错误请求了不存在的资源;
l 500:请求资源找到了,但服务器内部出现了错误;
l 302:重定向,当响应码为302时,表示服务器要求浏览器重新再发一个请求,服务器会发送一个响应头Location,它指定了新请求URL地址。
示例代码:
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(200);
response.sendError(404, "您要访问的资源不存在");
response.sendError(404);
}
}
使用response对象的setHeader()方法来设置响应头(头就是键值对,可能存在一个头:一个名称一个值;也可能存在多个头:一个名称多个值),使用该方法设置的响应头最终会发送给客户端浏览器。比如:content-Type、Refresh、Location等。
测试代码:
public class BServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setHeader("a", "AA"); // 单值
response.addHeader("b", "BB"); // 多值
response.addHeader("b", "BBB");
response.setIntHeader("c", 100);
response.setDateHeader("d", System.currentTimeMillis());
}
}
重定向是服务器通知浏览器去访问另一个地址,即再发出另外一个请求。操作步骤如下:
1. 响应码为302表示重定向,所以完成重定向的第一步就是设置响应码为302;
2. 重定向是通知浏览器发送第二个请求,即服务器需要告知浏览器第二个URL请求的地址,所以完成重定向的第二步是设置Location头,用以指定第二次请求的URL地址。
示例代码
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 重定向路径中的"/":表示客户端的根"http://locahost:8080/" response.setStatus(302);
response.setHeader("Location", "/servlet/BServlet"); // 访问BServlet 【URI】
response.getWriter().print(this);
}
}
上述代码的作用是:当访问完AServlet后,会通知浏览器重定向到BServlet。客户端浏览器解析到响应码位302后,就知道服务器让它重定向,所以它会马上获取响应头Location,然后发出第二个请求。
设置Refresh头,可以理解为“定时重定向(刷新)”。
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("欢迎回来,5秒钟后跳转到百度主页");
response.setHeader("Refresh", "5;url=http://www.baidu.com"); // url=/servlet/BServlet
Cache-Control、pragma、expires
response.setHeader("Cache-control", "no-cache");
response.setHeader("pragma", "no-cache");
response.setDateHeader("expires", -1);
注意:meta标签可以代替相应头:
设置响应类型/字符集。
(1) JSP页面定义:
(2) 等价于Servlet中定义响应头:
response.setContentType("text/html"); // MIME类型,参考%CATALINA%/conf/web.xml设置信息
response.setCharacterEncoding("utf-8")
(3) 等价于Sevlet中定义响应头:
response.setContentType("text/html;charset=utf-8");
(4) 等价于Servlet中定义响应头:
response.setHeader("content-type", "text/html;charset=utf-8")
设置content-type响应头,作用是告诉浏览器响应内容类型为html类型,同时设置response的字节流编码为utf-8。
在HTML页面中可以使用来指定响应头,例如在index.html页面中给出,表示浏览器只会显示index.html页面3
秒,然后自动跳转到http://www.baidu.com。 response.setHeader(“Refresh”, “3;url=http://www.baidu.com”)
响应体(响应正文)通常是html,也可以是图片等。
response是响应对象,向客户端输出响应正文(响应体)可以使用response的响应流,response提供了两个响应流对象:
(1) PrintWriter out = response.getWriter():获取字符流,用来向客户端发送字符数据,需要设置编码;
(2) ServletOutputStream out = response.getOutputStream():获取字节流,用来向客户端发送字节数据。
注意在一个请求中,不能同时使用这两个流!也就是说,要么使用response.getWriter(),要么使用response.getOutputStream(),但不能同时使用这两个流,否则会抛出IllegalStateException异常。
示例代码:使用ServletOutputStream发送字节数据(图片)
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext application = this.getServletContext();
// 在WebRoot/images/555.jpg
InputStream is = application.getResourceAsStream("/images/555.jpg");
// 导入commons-io.jar(拷贝到MyEclipse – WebRoot – WEB-INF - lib)
response.getOutputStream().write(IOUtils.toByteArray(is)); // InputStream --> byte[]
}
}
字符(流)编码
在使用response.getWriter()时需要注意默认字符编码是ISO-8859-1,如果希望设置字符流的编码为UTF-8,可以使用response.setCharacterEncoding(“utf-8”)来设置,这样可以保证输出给客户端的字符都是使用UTF-8编码的。
但客户端浏览器并不知道响应数据是什么编码的。如果希望通知客户端使用UTF-8来解读响应数据,那么还是使用response.setContentType(“text/html;charset=utf-8”)方法比较好,因为这个方法不仅调用response.setCharacterEncoding(“UTF-8”),还会设置content-type响应头,客户端浏览器会使用content-type头来解读响应数据。
字符流缓冲区
response.getWriter()是PrintWriter类型,所以它有缓冲区,缓冲区的默认大小是8KB。也就是说在响应数据没有输出8KB之前,数据都是存放在缓冲区中,而不是立刻发送到客户端。当Servlet执行结束后,服务器才会去刷新流,使缓冲区中的数据发送到客户端。
如果希望响应数据马上发送给客户端:(1)向流中写入大于8KB的数据;(2)调用response.flushBuffer()方法来手动刷新缓冲区。
客户端重定向response.sendRedirect(String URL)方法会设置响应头为302,同时设置Location响应头。服务器实际上已经向客户端产生了(302)响应,客户端(即浏览器)根据响应的HTTP Header中包含的Redirect地址,向服务器重新发起一个(GET方式)请求。需要注意的是,重定向发出的GET请求与最开始的那个请求不是同一个请求,这也意味着,在前一个请求中调用setAttribute()放进去的数据已经丢失!
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect(request.getContextPath() + "/hello/BServlet"); // 重定向的URL地址为:http://localhost/hello/BServlet
}
}
【重定向小结】
(1) 重定向是两次请求;
(2) 重定向的URL可以是其他应用,不局限于当前应用;
(3) 重定向的响应头是302,并且必须要有Location的响应头;
(4) 重定向就不要在使用response.getWriter()或response.getOutputStream()输出数据,不然可能会出现异常。