Servlet系列(二):常用接口
HttpServletRequest接口
由本系列前一篇文章我们可以发现,Servlet的开发就是针对不同的url编写对应的Servlet,这个Servlet一般只需要继承自HttpServlet
这个抽象类。这个抽象类针对不同的Http请求提供了不同的函数进行处理,如doGet()
,doPost()
等。这些函数都有HttpServletRequest
和HttpServletResponse
类型的两个参数,通过前者我们能够获取用户请求相关的信息,通过后者我们能够将请求的处理结果或数据库内容进行返回。
HttpServletRequest
接口继承自 ServletRequest
接口。HttpServletRequest
对象专门用于封装 HTTP 请求消息,简称 request
对象。
- 常用方法
返回类型 | 方法名 | 描述 |
---|---|---|
String | getMethod() | 获取Http请求方式 |
String | getRemoteAddr() | 获取客户端的 IP 地址。 |
String | getQueryString() | 获取请求行中的参数部分,也就是 URL 中“?”以后的所有内容。 |
String | getHeader(String name) | 该方法用于获取一个指定头字段的值。如果请求消息中包含多个指定名称的头字段,则该方法返回其中第一个头字段的值。 |
Enumeration | getHeaderNames() | 返回请求头中所有头字段的枚举集合。 |
String | getParameter(String name) | 返回指定参数名的参数值。 |
Enumeration | getParameterNames() | 以枚举集合的形式返回请求中所有参数名。 |
Map | getParameterMap() | 将请求中的所有参数名和参数值装入一个 Map 对象中返回。 |
HttpSession | getSession() | 获取一个HttpSession对象,当请求不存在Session对象时创建一个并返回 |
Cookie[] | getCookies() | 返回该请求包含的所有Cookie对象的一个数组 |
以上只列出了常用方法,所有的方法参见文档:https://docs.oracle.com/cd/E17802_01/products/products/servlet/2.5/docs/servlet-2_5-mr2/javax/servlet/http/HttpServletRequest.html
HttpServletResponse接口
HttpServletResponse
接口继承自 ServletResponse
接口。HttpServletResponse
对象专门用来封装 HTTP 响应消息,简称 response
对象。
- 常用方法
返回类型 | 方法名 | 描述 |
---|---|---|
void | setStatus(int status) | 设置 HTTP 响应消息的状态码,并生成响应状态行。 |
void | sendError(int sc) | 使用指定的状态码发送错误响应 |
void | addHeader(String name,String value) | 增加响应头字段,其中,参数 name 用于指定响应头字段的名称,参数 value 用于指定响应头字段的值。 |
void | addIntHeader(String name,int value) | 同上,但增加的响应头字段值为int类型 |
void | setHeader (String name,String value) | 设置响应头字段,其中,参数 name 用于指定响应头字段的名称,参数 value 用于指定响应头字段的值。 |
void | setIntHeader(String name, int value) | 同上,但设置的响应头字段值为int类型 |
void | setContentType(String type) | 设置 Servlet 输出内容的 MIME 类型以及编码格式。 |
void | setCharacterEncoding(String charset) | 设置输出内容使用的字符编码。 |
PrintWriter | getWriter() | 获取字符输出流对象 |
ServletOutputStream | getOutputStream() | 获取字节输出流对象 |
void | addCookie(Cookie cookie) | 添加cookie对象 |
中文乱码问题
request请求中文乱码
为了对request请求乱码进行测试,编写如下Servlet,在Post请求和Get请求中均读取名为parameter1
和parameter2
的两个参数并在控制台输出:
1 | public class HelloServlet extends HttpServlet |
- Post请求
我们构建如下表单向服务器发送带有中文参数的Post请求进行验证:
1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> |
当输入参数为「中文」和「Hello」时,控制台输出如下:
果然产生了乱码,这是因为用户浏览器默认编码为utf-8
,当用户通过Post请求提交的参数中包含中文时,Tomcat服务器采用默认编码方式ISO-8859-1
进行解码,这时控制台接收到的数据为乱码数据。
解决的办法就是在接收参数前设置参数的编码方式为utf-8
:
1 |
|
- Get请求
Get请求的参数出现在请求的url中,即?
后面的部分,我们很容易构造出如下带有中文的Get请求:
1 | http://localhost:8080/HelloServlet_war_exploded/hello?parameter1=中文¶meter2=hello |
结果是并没有出现乱码:
这是因为我电脑上的Tomcat版本为9,而Tomcat开发团队在8.x版本时就在底层设计上解决了Get请求中文乱码问题,即使请求参数中有中文也不会乱码了!
response中文乱码
- 通过字符流输出中文
尝试直接向PrintWriter
中写入中文输出:
1 |
|
出现乱码:
出现乱码的原因为:字符流输出内容存放在response的缓存区,而这个缓存区的默认字符编码为ISO-8859-1
,因此在用户浏览器使用utf-8
解码时出现乱码。
解决方法很简单,让response编码方式为utf-8
并通知浏览器用utf-8
方式解码即可:
1 |
|
- 通过字节流输出中文
1 |
|
使用字节流输出中文并不一定会乱码,这取决于中文转为字节数组时与浏览器打开采用的字符集是否一致。更加稳健的解决方式是采用utf-8
编码,并通知浏览器以该方式解码:
1 |
|
请求转发与重定向
请求转发
处理客户端请求时,有时需要多个资源相互配合,Servlet可以对请求进行一些处理之后将其传递给其它Web资源进行后续处理和响应,这种发生在服务器内部的传递行为称为「请求转发」。
请求转发需要通过RequestDispatcher
接口,该接口的实例可以通过调用ServletRequest
的 getRequestDispatcher(String path)
方法获得,参数用于指定目标资源的路径。
RequestDispatcher
提供了以下两个方法用于处理转发,通常调用forward方法:
1 | // 将请求转发给另一个 Web 资源。该方法必须在响应提交给客户端之前被调用,否则将抛出 IllegalStateException 异常 |
需要注意:
- 请求转发不支持跨域访问,只能访问当前应用的资源。
- 请求转发浏览器地址栏URL不会发生变化,即用户无法知道服务器的转发行为。
- 参与请求转发的Web资源共享同一request 对象和 response 对象。
- 由于 forward() 方法会先清空 response 缓冲区,因此只有转发到最后一个 Web 资源时,生成的响应才会被发送到客户端。
实现转发很简单:
1 |
|
实际上request对象是Servlet三大域对象之一(这些域对象将在后续进行总结),这意味着在request对象上绑定一些属性,即在request对象上携带一些对象,配合转发能够实现数据的传递。这主要通过以下request对象上的方法实现:
1 | // 给request对象绑定一个属性,名称为name,属性值为对象o |
重定向
相比于请求转发,重定向是客户端的行为,服务器接收到客户端请求之后,告诉客户端重新向另一个URL发送请求,这个过程为重定向。重定向本质上是两次HTTP请求,故浏览器地址栏的URL会发生变化。
通过response.sendRedirect(String location)
方法实现重定向:
1 |
|
总结
本文首先介绍了request对象和response对象上的一些方法,然后归纳了Servlet请求和响应时容易出现的中文乱码问题,最后总结了转发和重定向之间的区别和实现方法。