从HttpURLConnection获取InputStream对象时发生FileNotFoundException


109

我正在尝试使用HttpURLConnection(在Java中使用cUrl)将发布请求发送到url。请求的内容为xml,最后,应用程序处理xml并将记录存储到数据库,然后以xml字符串的形式发送回响应。该应用程序本地托管在apache-tomcat上。

当我从终端执行此代码时,将按预期将一行添加到数据库。但是,从连接获取InputStream时会引发如下异常

java.io.FileNotFoundException: http://localhost:8080/myapp/service/generate
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1401)
    at org.kodeplay.helloworld.HttpCurl.main(HttpCurl.java:30)

这是代码

public class HttpCurl {
    public static void main(String [] args) {

        HttpURLConnection con;

        try {
            con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();
            con.setRequestMethod("POST");
            con.setDoOutput(true);
            con.setDoInput(true);

            File xmlFile = new File("test.xml");

            String xml = ReadWriteTextFile.getContents(xmlFile);                

            con.getOutputStream().write(xml.getBytes("UTF-8"));
            InputStream response = con.getInputStream();

            BufferedReader reader = new BufferedReader(new InputStreamReader(response));
            for (String line ; (line = reader.readLine()) != null;) {
                System.out.println(line);
            }
            reader.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
  }

它令人困惑,因为异常被跟踪到该行,InputStream response = con.getInputStream();并且FileNotFoundException似乎没有涉及任何文件。

当我尝试直接打开与xml文件的连接时,它不会引发此异常。

服务应用程序使用spring框架和Jaxb2Marshaller创建响应xml。

类ReadWriteTextFile从这里获取

谢谢。

编辑: 好吧,它将数据保存在DB中,并同时发送回404响应状态代码。

我还尝试使用php进行卷曲,并打印出CURLINFO_HTTP_CODE结果为200。

关于如何进行调试的任何想法?服务和客户端都在本地服务器上。

解决: 参考SO本身的答案后,我可以解决问题。

似乎使用非标准端口连接到URL时,HttpURLConnection总是返回404响应。

添加这些行解决了它

con.setRequestProperty("User-Agent","Mozilla/5.0 ( compatible ) ");
con.setRequestProperty("Accept","*/*");

1
“当我从终端执行此代码时”-哪个代码?目前尚不清楚什么在起作用,什么在不起作用。
乔恩·斯基特

HttpCurl是具有此主要方法的类的名称。该类被编译并从终端上运行
naiquevin

3
我遇到了同样的问题,但是这里没有解决方案。我最终发现这是Java 1.7.0_05的问题,并已更新至最新版本1.7.0_21,该问题消失了。我还意识到在Java 1.6中没有发生该问题。仅供仍陷于困境的任何人参考。
2013年

伙计们!请参阅对问题而非答案的“已解决”评论!
2015年

Answers:


130

我不了解您的Spring / JAXB组合,但是一般的REST Web服务不会在POST / PUT上返回响应正文,而只会返回响应状态。您想确定它而不是身体。

更换

InputStream response = con.getInputStream();

通过

int status = con.getResponseCode();

HTTP规范中提供了所有可用的状态码及其含义,如前所述。Web服务本身还应随附一些文档,其中概述了Web服务支持的所有状态代码及其特殊含义(如果有)。

如果状态以4nn或开头5nn,则您想getErrorStream()改用阅读可能包含错误详细信息的响应正文。

InputStream error = con.getErrorStream();

好的,我尝试了一下,它返回状态404。但是奇怪的是,它也保存在DB中!同样从您提到的内容来看,这是否意味着任何REST服务都只会返回状态码?如果发布成功,我想返回更多信息,例如xml验证错误消息或url,该怎么办?
naiquevin 2011年

是的,在诸如POST / PUT / etc之类的修改请求中,它通常不会返回正文。通常,您希望在读取输入或错误流之前确定响应状态。我在答案中添加了一些细节。但是,如果它确实返回状态404,则说明Web服务中可能存在一些错误。我会向其维护者报告。
BalusC

在这种情况下,服务的维护者恰好是我!..好吧,我尝试使用php进行curl,它返回200(已编辑了我的问题)也尝试getErrorStream()按照建议进行操作。会在抛出NullPointerException new InputStreamReader(con.getErrorStream())
naiquevin 2011年

抱歉,我不熟悉Spring Web服务。我仅动手使用标准Java EE 5/6 API的JAX-WS / RS经验。我建议在负责处理XML文件的方法上设置一个断点,然后从那里进一步走。
BalusC

这种行为似乎非常无用,特别是因为它使引用URLConnection问题变得更加笼统。我不知道为什么在Java家伙并没有简单地实现getInputStream()HttpUrlConnection沿着线return responseCode == 200 ? super.getInputStream() : this.getErrorStream()。但是无论如何;内容丰富的答案,+ 1。
aroth

51

FileNotFound 只是一个不幸的异常,用于指示Web服务器返回了404。


1
这不能解释为什么OP会将该行添加到数据库中。
BalusC,

@BalusC:除非将服务器添加行和然后返回一个404
乔恩斯基特

是的,它似乎以这种方式表现。这是什么意思 ?
naiquevin 2011年

@naiquevin:很难说,但是鉴于它是在本地运行的服务,因此您应该可以自己调试它。
乔恩·斯基特

7
HttpURLConnection还为403响应(可能还有其他响应)抛出FileNotFoundException。(看起来,即使响应主体不是空的。)无论如何,请始终getResponseCode()在调用之前进行调查getInputStream()
约尼克,

29

对于将来有此问题的任何人,原因是因为状态代码是404(或者在我的情况下是500)。InpuStream当状态码不是200时,似乎该函数将引发错误。

就我而言,我控制自己的服务器,并返回500状态代码以指示发生了错误。尽管我还向正文发送了带有错误详细信息的字符串消息,但inputstream无论正文是否完全可读,都引发了错误。

如果您控制服务器,我想可以通过向自己发送200状态代码然后处理任何字符串错误响应来解决。


21
需要明确的是,您只是在处理错误。您应该使用connection.getResponseCode来检查它是否正确。然后使用connection.getErrorStream而不是getInputStream来获取错误正文。(或者您可以使用getResponseMessage)如果出现错误,则不应发送200状态代码,请按预期使用http错误代码。
rekh127 2014年

5

对于其他为此绊脚石的人,在尝试向SOAP服务发送SOAP请求标头时,我也遇到了同样的情况。问题是代码顺序错误,在发送XML主体之前,我先请求了输入流。在下面的代码片段中,InputStream in = conn.getInputStream();紧接其后的一行ByteArrayOutputStream out = new ByteArrayOutputStream();是错误的顺序。

ByteArrayOutputStream out = new ByteArrayOutputStream();
// send SOAP request as part of HTTP body 
byte[] data = request.getHttpBody().getBytes("UTF-8");
conn.getOutputStream().write(data); 

if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) {
  Log.d(TAG, "http response code is " + conn.getResponseCode());
  return null;
}

InputStream in = conn.getInputStream();

FileNotFound 在这种情况下,这是编码HTTP响应代码400的一种不幸方式。


FileNotFound是因为该连接没有uput流。它与对响应代码400进行编码无关。您可以使用getResponseCode()获得响应代码。然后,如果不是HTTP_OK,则应使用conn.getErrorStream()或getResponseMessage()获得正文
rekh127 2014年

new ByteArrayOutputStream()与它无关。问题是介于getInputStream()和之间的顺序getResponseCode()
罗恩侯爵

4

在这种情况下,FileNotFound意味着您从服务器上获得了404-可能是服务器不喜欢“ POST”请求吗?


但是它确实将记录保存到数据库。Jaxb2Marshaller可能是这里的问题吗?
naiquevin 2011年

2
这不仅发生在404上。空着的身体也会发生任何反应。
戴夫·卡梅隆

3
不幸的是,这个答案是错误的。在这种情况下,FileNotFound表示仅当响应代码高于399时才调用HttpURLConnection#getInputStream(),而在这种情况下应调用HttpURLConnection#getErrorStream()。OTOH,如果服务器不接受POST,它将返回405 Method Not Allowed。与FileNotFound无关。
Michal M

0

解决方案: 如果您想知道以下信息,
只需将localhost更改为PC 的IP
Windows + r> cmd> ipconfig
示例:http:// 192.168.0.107 /directory/service/program.php?action=send
可以将某些内容替换为192.168 .0.107作为您自己的IP(不要尝试127.0.0.1,因为它与localhost相同)


-4

请更换

con = (HttpURLConnection) new URL("http://localhost:8080/myapp/service/generate").openConnection();

con = (HttpURLConnection) new URL("http://YOUR_IP:8080/myapp/service/generate").openConnection();

2
为什么要更改OP特别声明该服务在本地运行。
罗恩侯爵

万一您需要从本地主机获取图像资源,它将无法正常工作。
Phuoc Huynh
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.