出处:http://blog.youkuaiyun.com/baoyiming1991/article/details/5972989
转发的原理:
图片来自:http://blog.sina.com.cn/s/blog_4a157f470100a86y.html?retcode=0
浏览器将请求发送至servlet容器后,相应的组件获取到这个请求,然后在其内部将这个请求转发(request, response)给另外一个组件2,然后有组件2来响应浏览器的请求,但是此时浏览器上看到的仍然是组件1的地址。
在转发中,实际上转发的只有request,返回个浏览器的response的内容仍然是组件1中的设置。看下面代码:
IncludingServlet.java
- import java.io.IOException;
- import java.io.PrintWriter;
- import javax.servlet.RequestDispatcher;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class IncludingServlet extends HttpServlet {
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- resp.setContentType("text/html;charset=UTF-8");
- PrintWriter out = resp.getWriter();
- String china = "中国";
- RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher(
- "/IncludedServlet?p1=" + china);
- out.println("Before including<br />");
- requestDispatcher.include(req, resp);
- out.println("After including<br />");
- }
- }
IncludedServlet.java
- import java.io.IOException;
- import java.io.PrintWriter;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class IncludedServlet extends HttpServlet {
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- resp.setContentType("text/html;charset=UTF-8");
- resp.setCharacterEncoding("UTF-8");
- PrintWriter out = resp.getWriter();
- out.println("中国<br />");
- out.println("URI:" + req.getRequestURI() + "<br />");
- out.println("QueryString:" + req.getQueryString() + "<br />");
- out.println("Parameter p1:" + req.getParameter("p1") + "<br />");
- }
- }
*代码源自《Java Web开发内幕——核心基础》
在web.xml文件中注册上面两个servlet,运行tomcat,在浏览器中输入对IncludingSerlvet的请求,得到结果:
这里面正确地显示出了“中国”两个UTF-8编码的字符,但看上面的代码可以发现,两段代码都对response进行了设置文字编码操作,那究竟是哪一个设置起的作用?
尝试将IncludingServlet.java中的response的操作注释掉,再看结果,如下:
此时中国两个字显示成了乱码,这就说明了被转发的Servlet不能改变响应消息的状态码和响应头,同样,无法修改HttpServletRespnse对象中的信息。同样也看到了虽然IncludingServlet转发给了IncludedServlet,但是浏览器地址栏显示的还是调用者IncludingServlet的URI。
再来讨论另外一种情况,在servlet文件目录下新建一个chinese.html文件,内容为:
- <s>这是一句被划掉的文字<s>
修改IncludingServlet.java文件的代码如下:
- import java.io.IOException;
- //import java.io.PrintWriter;
- import javax.servlet.RequestDispatcher;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- public class IncludingServlet extends HttpServlet {
- @Override
- protected void service(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
- //resp.setContentType("text/html;charset=UTF-8");
- //resp.setCharacterEncoding("UTF-8");
- //PrintWriter out = resp.getWriter();
- //String china = "中国";
- //RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher(
- // "/IncludedServlet?p1=" + china);
- RequestDispatcher requestDispatcher = this.getServletContext().getRequestDispatcher(
- "/chinese.html");
- //out.println("Before including<br />");
- requestDispatcher.include(req, resp);
- //out.println("After including<br />");
- }
- }
运行结果如下:
如果直接访问这个页面,得到如下结果:
为什么经过转发以后就不能解析html内容了呢?即,为什么直接访问html页面所得到的相映消息中包好Content-Type字段而通过IncludingServlet转发的则不包含呢?
解释是,凡是在web.xml中找不到匹配<servlet-mapping>元素的URL请求,也就是其他Serlvet都不处理的请求,都将交给tomcat的一个缺省servlet来处理,客户端对静态html的访问时间上就是在调用这个缺省servlet来完成响应的。所以,调用一个html和调用一个servlet本质上是一样的。
故在上面例子中,在IncludingServlet.java中加上
- resp.setContentType("text/html";charset=UTF-8");
这样就能得到正确的输出了。
在一个问题,ServletContext中的getRequestDispatcher方法和Request中的getRequestDispatcher方法的不同之处:ServletContext中的getRequestDispatcher方法在指定URI时不能使用相对地址,而Request中的getRequestDispatcher方法可以。