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