读取输入后无法写入输出

17
我正在编写一个程序,通过HttpURLConnection连接到一个servlet,但是我在检查url时遇到了困难。
public void connect (String method) throws Exception {

server = (HttpURLConnection) url.openConnection ();
server.setDoInput (true);
server.setDoOutput (true);
server.setUseCaches (false);
server.setRequestMethod (method);
server.setRequestProperty ("Content-Type", "application / xml");

server.connect ();

/*if (server.getResponseCode () == 200)
{
System.out.println ("Connection OK at the url:" + url);
System.out.println ("------------------------------------------- ------- ");
}
else
System.out.println ("Connection failed"); 

}*/

我遇到了以下错误:

java.net.ProtocolException: Cannot write output after reading input.

如果我使用注释中的代码检查URL,它可以正常工作,但不带注释的代码出现该错误。不幸的是,我需要检查URL,所以我认为问题出在getResponseCode方法上,但我不知道如何解决。

非常感谢。

4个回答

30

HTTP协议基于请求-响应模式:首先您发送请求,然后服务器响应。一旦服务器做出响应,您就无法再发送任何内容,这是没有意义的。(在服务器不知道您尝试发送什么之前,它怎么可能为您提供响应代码呢?)

因此,当您调用server.getResponseCode()时,实际上是告诉服务器您的请求已经完成,并且可以处理它。如果您想发送更多数据,您必须启动一个新请求。

查看您的代码,您想检查连接本身是否成功,但没有必要这样做:如果连接不成功,server.connect()会抛出一个Exception。但连接尝试的结果与HTTP响应代码不同,后者始终在服务器处理完所有输入后到达。


非常感谢。实际上,我在连接控制和HTTP响应控制之间产生了误解。我通过try catch进行了切换,现在它的效果更好了。 - ulquiorra
但是在我完成POST之前,服务器可能会响应错误。如何使用HttpURLConnection读取早期响应? - Jiang YD
@ulquiorra,我认为我正在遇到这个问题。有一个getResponseCode()后面跟着一个getOutputStream();。你认为这会导致Cannot write output after reading input吗? - Mushy

8
我认为异常不是由于打印URL引起的。肯定有一些代码在读取响应后尝试编写请求主体。
如果在获取HttpURLConnection.getInputStream()后尝试获取HttpURLConnection.getOutputStream(),则会出现此异常。
以下是sun.net.www.protocol.http.HttpURLConnection.getOutputStream的实现:
public synchronized OutputStream getOutputStream() throws IOException {

     try {
         if (!doOutput) {
             throw new ProtocolException("cannot write to a URLConnection"
                            + " if doOutput=false - call setDoOutput(true)");
         }

         if (method.equals("GET")) {
             method = "POST"; // Backward compatibility
         }
         if (!"POST".equals(method) && !"PUT".equals(method) &&
             "http".equals(url.getProtocol())) {
             throw new ProtocolException("HTTP method " + method +
                                         " doesn't support output");
         }

         // if there's already an input stream open, throw an exception
         if (inputStream != null) {
             throw new ProtocolException("Cannot write output after reading 
                input.");
         }

         if (!checkReuseConnection())
             connect();

         /* REMIND: This exists to fix the HttpsURLConnection subclass.
          * Hotjava needs to run on JDK.FCS.  Do proper fix in subclass
          * for . and remove this.
          */

         if (streaming() && strOutputStream == null) {
             writeRequests();
         }
         ps = (PrintStream)http.getOutputStream();
         if (streaming()) {
             if (strOutputStream == null) {
                 if (fixedContentLength != -) {
                     strOutputStream = 
                        new StreamingOutputStream (ps, fixedContentLength);
                 } else if (chunkLength != -) {
                     strOutputStream = new StreamingOutputStream(
                         new ChunkedOutputStream (ps, chunkLength), -);
                 }
             }
             return strOutputStream;
         } else {
             if (poster == null) {
                 poster = new PosterOutputStream();
             }
             return poster;
         }
     } catch (RuntimeException e) {
         disconnectInternal();
         throw e;
     } catch (IOException e) {
         disconnectInternal();
         throw e;
     }
 }

感谢您的帮助。实际上,我的异常是由以下代码引起的:BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(server.getOutputStream(), "UTF-8"))。但是,我的类非常长,所以我决定只在注释中放置主要问题的代码。 - ulquiorra
是的,您只能在获取server.getInputStream()之前这样做。在此之后就不行了。 - Ramesh PVK

3
我也遇到了这个问题,令我惊讶的是错误是由我添加的代码 System.out.println(conn.getHeaderFields()); 引起的。
以下是我的代码:
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
configureConnection(conn);
//System.out.println(conn.getHeaderFields()); //if i comment this code,everything is ok, if not the 'Cannot write output after reading input' error happens
conn.connect();
OutputStream os = conn.getOutputStream();
os.write(paramsContent.getBytes());
os.flush();
os.close();

2
我有同样的问题。 解决这个问题的方法是你需要使用这个序列。
openConnection -> getOutputStream -> write -> getInputStream -> read

这意味着...:
public String sendReceive(String url, String toSend) {
URL url = new URL(url);
URLConnection conn = url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.sets...

OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
out.write(toSend);
out.close();

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String receive = "";
do {
    String line = in.readLine();
    if (line == null)
        break;
    receive += line;
} while (true);
in.close();

return receive;
}

String results1 = sendReceive("site.com/update.php", params1);
String results2 = sendReceive("site.com/update.php", params2);
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接