重定向区别于转发,是客户端请求服务器,服务器的两种操作方式:
1.重定向 :通俗的说-客户端向服务器发出一次请求,服务器作出响应告诉客户端去请求另外一个地址,客户端请求了两次,得到响应两次。
2,转发:也是通俗的说-客户端向服务器发出一次请求,服务器去请求另外一个地址,然后作出响应,客户端请求了一次,得到响应一次。
我们这里就从Servlet说说转发:(javaweb的一些框架都是基于servlet开发的)
我们要转发,就得先得到Dispatrue对象,然后调用它的forword(request,response);方法,进行请求转发。
得到Dispatrue对象有两种方式:
1,|--得到ServletContext(),然后通过它的getRequestDispatrue()方法得到;
|--得到ServletContext对象有两种方式:
1.1.|--通过ServletConfig对象的getServletContext()方法获取;
1.1.1|--得到ServletConfig对象,通过httpServlet自带的方法getServletConfig()方法获取。
1.2.|--则是通过HttpServlet自带的方法getServletContext()方法获取。
2,|--通过Request对象的getRequestDispatrue()方法得到。
我们对下面的代码进行分析,更加深刻的理什么是转发:
ServletContext context=getServletContext();
OutputStream os=response.getOutputStream();
os.write("ss".getBytes());
//os.flush();//flush将缓冲区的数据强制性的写到客户端后response就返回给客户端信息导致本次响应结束,,后面的不执行,如果不flush那么
//在执行转发前 缓冲区的数据就会被清空
System.out.println("执行了");
context.getRequestDispatcher("/ResponseGzipTest").forward(request, response);
response.getOutputStream().write("vbb".getBytes());//这个不执行,以为转发后目的地的response已经向客户端写信息了
//那么这个response就无效了,和前面的情况是一样的
上面程序中的:
ResponseGzipTest 是一个Servlet 具体代码如下:
response.setContentType("text/html;charset=utf-8");
response.setHeader("Content-Encoding", "gzip");
String s="hello niha";
System.out.println(s.getBytes().length);
ByteOutputStream out=new ByteOutputStream();
GZIPOutputStream gos=new GZIPOutputStream(out);
gos.write(s.getBytes());//将数据压缩读出来放入到out字节输出流中
gos.close();
byte []buf=out.toByteArray();
OutputStream ous=response.getOutputStream();
System.out.println(buf.length);
ous.write(buf);
ous.close();
上面的代码是将"hello niha"通过gzip压缩后传输到客户端显示出来。
分析:当客户端一个请求到通过get或者post方式到达后台时,程序进行的时候,执行到了红色部分的代码,那么后台服务器就得进行转发这个请求,通过forword代码将这次请求的request对象和response对象传递过去(因为一次请求进行转发,只有一个request和response),
这是这个程序的运行结果:
我们可以看到在地址栏我们请求的是ServletContextTest2然后转发到ResponseGzipTest这个servlet,这里地址栏的url没有发生变化(这是转发的一个特点),
但是我们在图上面的第一段代码的时候,在转发前存在这么一段代码:
OutputStream os=response.getOutputStream();
os.write("ss".getBytes());
//os.flush();//flush将缓冲区的数据强制性的写到客户端后response就返回给客户端信息导致本次响应结束,,后面的不执行,如果不flush那么
//在执行转发前 缓冲区的数据就会被清空
System.out.println("执行了");
为什么os.write("ss".getBytes())这句话没有起作用,也就是说为什么页面上没有打印出来“ss”这个字符串?
原因是这样的:
os.write("ss".getBytes())是将“ss”写进了缓存,每当服务器进行转发的时候,都会清除缓存中的数据所有不会有输出结果。
但是如果我们将注释掉的“os.flush()“释放掉,会出现怎样的结果呢?
这个是执行结果,也就是说这次将ss输出到了页面;但是控制台出现了异常:
说的是响应已经提交,也就是说转发的时候不存在没有提交的response,为什么会出现这种情况呢?
原因是:我们调用os.flush()方法,强制的将缓存中的数据通过response的响应写到客户端,那么就意味着这次请求就结束了。
我们还注意到在第一段代码的转发后存在这么一段代码:
response.getOutputStream().write("vbb".getBytes());//这个不执行,以为转发后目 //的地的response已经向客户端写信息了
这句换在上面的几种情况下都没有执行,为什么呢?
原因是:第一种情况是转发执行了,在ResponseGizpTest这个servlet类里面已经通过response对客户端做出了响应,那么其后执行的所有response就失效了。
第二种情况,是强制flush缓存中的数据,通过response响应想客户端写数据, 其后的response当然也就失效了。。