摘自:http://blog.csdn.net/quechao123/article/details/6256653

  • 异常一:java.lang.IllegalStateException:Cannot   forward   a   response   that   is   already   committed 
    异常二:IllegalStateException:response already commited 
    异常三:IllegalStateException:getOutputStream() has already been called for this request

前言:

response是服务端对客户端请求的一个响应,其中封装了响应头、状态码、内容(也就是最终要在浏览器上显示的HTML代码或者其他数据格式)等,

  服务端在把response提交到客户端之前,会使用一个缓冲区,并向该缓冲区内写入响应头和状态码,然后将所有内容flush(flush包含两个步骤:先将缓冲区内容发送至客户端,然后将缓冲区清空)。这就标志着该次响应已经committed(提交)。对于当前页面中已经committed(提交)的response,就不能再使用这个response向缓冲区写任何东西  (注:以为JSP中,response是一个JSP页面的内置对象,所以同一个页面中的response.XXX()是同一个response的不同方法,只要其中一个已经导致了committed,那么其它类似方式的调用都会导致 IllegalStateException异常)。

对于异常一:

问题描述

在执行一段代码后,最后执行request.getRequestDispatcher(跳转页面URL).forward(resquest,response)进行页面跳转时,报了此错

问题原因

1.在forwar之前,response就已经commit到浏览器端了。

导致response commit的原因包括:forward, redirect, flushBuffer

2.前两个原因都是指在forward之前就已经进行了页面跳转动作(forward, redirect)。

于flushBuffer,每一个JSP页面都有一个缓冲区,默认的缓冲区大小为8KB,如果缓冲区被占满的话,web服务器就会自动将response 进行commit,然后清空缓冲区(即flush),所以再进行页面跳转的时候就会报response已经被commit了。

内置对象out相关方法

public abstract void clear() throws java.io.IOException 清除缓冲区中的内容。如果缓冲区已经被刷新,clear()方法将抛出IOException异常
public abstract void clearBuffer() throws java.io.IOException 清除缓冲区中的当前内容。这个方法和clear()方法的区别是,如果缓冲区已经被刷新,这个方法不会抛出IOException异常
public abstract void close() throws java.io.IOException

刷新缓冲区,关闭输出流。注意,我们在编写JSP页面时,不需要显式地去调用这个方法,因为在JSP容器所生成的代码中会自动包含对close()方法的调用。

public abstract void flush() throws java.io.IOException 刷新缓冲区,两个步骤:1,提交response  2.清空缓冲区
public int getBufferSize() 获得缓冲区大小,同response.getBufferSize()相同
public abstract int getRemaining() 获得缓冲区中未使用的字节数
public boolean isAutoFlush() 判断out对象是否是自动刷新 
<%@ page autoFlush="true" %> <%--Default--%>

内置对象response相关方法

response.isCommitted() 确认response是否已经committed
response.flushbuffer(); 同out.flush相同

解决方法:

增大缓冲区大小:

<%@ page buffer="10kb" %>

参考:http://jorton468.blog.163.com/blog/static/72588135201102441617287/

附加:

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

问题描述:

错误类型大致为以下几种:

java.lang.IllegalStateException:Cannot   forward   a   response   that   is   already   committed 
IllegalStateException:response already commited 
IllegalStateException:getOutputStream() has already been called for this request
…………

 

错误原因:

该异常表示,当前对客户端的响应已经结束,不能在响应已经结束(或说消亡)后再向

                       客户端(实际上是缓冲区)输出任何内容。

具体分析:

                        首先解释下flush(),我们知道在使用读写流的时候数据先被读入内存这个缓冲区中,

                         然后再写入文件,但是当数据读完时不代表数据已经写入文件完毕,因为可能还有

                         一部分仍未写入文件而留在内存中,这时调用flush()方法就会把缓冲区的数据强行

                         清空输出,因此flush()的作用就是保证缓存清空输出。

                        response是服务端对客户端请求的一个响应,其中封装了响应头、状态码、内容等,

                        服务端在把response提交到客户端之前,会向缓冲区内写入响应头和状态码,然后

                        将所有内容flush。这就标志着该次响应已经committed(提交)。对于当前页面中

                        已经committed(提交)的response,就不能再使用这个response向缓冲区写任何东西

                     (注:同一个页面中的response.XXX()是同一个response的不同方法,只要其中一个

                        已经导致了committed,那么其它类似方式的调用都会导致 IllegalStateException异常)。

【注意】能够导致响应已经committed的操作包括:forward, redirect, flushBuffer

JDK API:

         

flushBuffer

        public void flushBuffer()throws IOException
Forces any content in the buffer to be written to the client. A call to this method automatically commits the response, meaning the status code and headers will be written.  
           ②
                

sendRedirect

         public void sendRedirect(String location)throws IOException
Sends a temporary redirect response to the client using the specified redirect location URL. This method can accept relative URLs; the servlet container must convert the relative URL to an absolute URL before sending the response to the client. If the location is relative without a leading '/' the container interprets it as relative to the current request URI. If the location is relative with a leading '/' the container interprets it as relative to the servlet container root.

If the response has already been committed, this method throws an IllegalStateException. After using this method, the response should be considered to be committed and should not be written to.


forward

public void forward(ServletRequest request,ServletResponse response)
                             throws ServletException,IOException
Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server. This method allows one servlet to do preliminary processing of a request and another resource to generate the response.

For a RequestDispatcher obtained via getRequestDispatcher(), the ServletRequest object has its path elements and parameters adjusted to match the path of the target resource.

forward should be called before the response has been committed to the client (before response body output has been flushed). If the response already has been committed, this method throws anIllegalStateExceptionUncommitted output in the response buffer is automatically cleared before the forward.

The request and response parameters must be either the same objects as were passed to the calling servlet's service method or be subclasses of the ServletRequestWrapper or ServletResponseWrapper classes that wrap them.

 

备    注:

在一次响应commit之前,所有的内容输出都将写入servlet引擎的缓冲区(tomcat或

                  weblogic的内容空间), 而在commit之后,上一次response向缓冲区写入的内容,将清空。

                  由于servlet在没有设置单线程的情况下(使用Single-Threaded Model,servlet实现

                  SingleThreadModel接口,jsp使用<%@ page isThreadSafe="false" %>),是多线程的,所以

                  上面所说的缓冲区,都将是该response所属的线程私有的内存空间。有了这个概念,

                  将可以分析碰到的关于servlet多线程的很多问题。

                  如果不能确认response是否已经committed. 可以调用response.isCommitted()来判断。

                  导致这个错误最普遍的原因是,jsp有编译错误。

常见解决办法:

                 ①在response.sendRedirect()方法后加return语句即可,如下:
                       response.sendRedirect("login.jsp");
                       return;
                 ②检查提交的url是否有误。

                 ③如果你的页面中用了清缓存代码response.flushbuffer();又用到了response.sendRedirect(url);

                     你可以把response.flushbuffer();去掉,或者用JS的window.location.href="url";来做转向。

                 ④如果你用了OutputStream,而web容器生成的servlet代码中有out.write(””),这个和JSP中调用的

                     response.getOutputStream()冲突。out.write()这个是字符流,而response.getOutputStream()

                    是字节流,你不能在同一个页面中调用多个输出流。无论先调用哪一个,在调用第二个时都会抛出

                      IllegalStateException,因为在jsp中,out变量是通过response.getWriter得到的。在多个使用了

                     outputStream的<%%>语句之间不能有空格及多余的字符。也就是页面中除了使用了

                      outputStream的<%%>之外不能有空格或其它任何字符,在之内的语句可以有空格及回车。

                 在JSP页面做输出的时候有两种方式.一是通过JspWriter,另一个是通过

                 OutputStream,但二者互相排斥.如果并存的话就会报告以上异常.                     

                     在不得不使用OutputStream的时候.我们必须要把JspWriter舍弃掉了。找到

                     请求异常的页面所对应的Servlet..把其中所有使用JspWriter的语句全部去掉.

                     或者是到你的JSP文件里把动态输出的代码注释掉.这里注意换行和空格制表符

                     为JspWriter输出.应该一起去掉.保存文件重新启动服务器你会发现上述异常

                     消失了。                    

         由于jsp container在处理完成请求后会调用releasePageContet方法释放
          所用的PageContext object,并且同时调用getWriter方法,由于getWriter方法
          与在jsp页面中使用流相关的getOutputStream方法冲突,所以会造成这种异常,
         解决办法是:只需要在jsp页面的最后加上两条语句:   
                 out.clear(); 
                 out=pageContext.pushBody();
         即可(其中out,pageContext均为jsp内置对象!) 。

response提交原理(转)的更多相关文章

  1. 【Spark Core】TaskScheduler源代码与任务提交原理浅析2

    引言 上一节<TaskScheduler源代码与任务提交原理浅析1>介绍了TaskScheduler的创建过程,在这一节中,我将承接<Stage生成和Stage源代码浅析>中的 ...

  2. 表单 - Form - 无刷新提交原理

    为什么Form组件的表单提交可以做到无刷新? EasyUI在提交的时候,将表单作为一个隐藏的iframe进行的提交,并不是我们看到的那个表单进行的提交 并且那个iframe使用了绝对定位,保证页面上不 ...

  3. SQLite的原子提交原理

    本文描述了sqlite为保证数据库文件不被损坏而采取的种种手段.. 以下是原译者的摘要:http://www.kuqin.com/shuoit/20150618/346693.html 摘要: 本文源 ...

  4. sqlite原子提交原理

    英文地址 文章参考 简介 支持事务的数据库系统如sqlite的一个重要特性是原子提交(atomic commit).也就是在一个事务中进行的对数据库的写操作要么全部执行,要么全部不执行.看起来像是对数 ...

  5. git原理:提交原理

    当运行git add  git commit的时候,git底层都做了什么? 这里涉及到的底层命令:git hash-object 讲对象写入到git object中git update-index   ...

  6. Response.Redirect原理图解

  7. flink-----实时项目---day07-----1.Flink的checkpoint原理分析 2. 自定义两阶段提交sink(MySQL) 3 将数据写入Hbase(使用幂等性结合at least Once实现精确一次性语义) 4 ProtoBuf

    1.Flink中exactly once实现原理分析 生产者从kafka拉取数据以及消费者往kafka写数据都需要保证exactly once.目前flink中支持exactly once的sourc ...

  8. request 对象和 response 对象

    Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象.和代表响应的response对象 HttpServletResponse HttpServletR ...

  9. Spring系列.@EnableRedisHttpSession原理简析

    在集群系统中,经常会需要将Session进行共享.不然会出现这样一个问题:用户在系统A上登陆以后,假如后续的一些操作被负载均衡到系统B上面,系统B发现本机上没有这个用户的Session,会强制让用户重 ...

随机推荐

  1. xshell无法连接Ubuntu的解决办法

    使用workstations14安装完Ubunu后,网络连接方式为NAT模式(N):用于共享主机的IP地址 此时想用xshell连接此虚拟机但是提示连接失败,但是宿主机和虚拟机互相都能ping通,且虚 ...

  2. Java 连接、操控数据库总结(JDBC)

    看到数据库连接不由得想起了大一末参加团队考核时的悲催经历~~,还记得当初傻傻地按照书本的代码打到 Eclipse 上,然后一运行就各种报错...报错后还傻傻地和书本的代码一遍又一遍地进行核对,发现无误 ...

  3. mysql 循环插入

    在mysql添加测试数据,想和mssql一样用循环实现,发现不管怎么样都执行失败 经查询发现mysql不支持匿名块,只能先创建出一个存储过程,执行,然后删除 CREATE PROCEDURE test ...

  4. SQL Data Base 不装oracle客户端连接oracle服务端

    SQL Data Base  不装oracle客户端连接oracle服务端 一.直连: devart 二.拷贝dll: Oracle.DataAccess.dlloci.dllociw32.dll

  5. [Perl]通过GD模块获取字符/汉字的点阵

    原来Perl获取汉字的点阵如此简单 示例脚本应保存为utf8格式 Code: [全选] [展开/收缩] [Download] (Untitled.pl) use GD; use utf8; my $g ...

  6. Oracle-利用解析函数计算连续、回流

    ---最大连续交易天数 select t2.customer_no,max(t2.co) from (select t1.customer_no,t1.yp) co from (select ctd. ...

  7. day04.1-三元表达式与列表解析

    1. 三元表达式 name = input("请输入:") res = "英雄" if name=="令狐冲" else "伪君子 ...

  8. 在linux 创建网络会话和绑定两块网卡

    1. 如果我们在公司网络中要手动指定网络的IP地址,当我们回到家里则是使用DHCP(动态主机配置协议)自动分配IP地址.这就有点麻烦了,因为要频繁的修改IP地址,所以接下来我们来创建网络会话----- ...

  9. [ActionScript 3.0] 框选裁剪

    package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Loader; ...

  10. Python多继承的C3算法

    C3算法 一.知识点补充: 拓扑排序:在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且 ...