1. 程式人生 > >HttpURLConnection拋異常java.io.FileNotFoundException

HttpURLConnection拋異常java.io.FileNotFoundException

今天在除錯app的時候,用HttpURLConnection獲取伺服器資料的時候出現了java.io.FileNotFoundException異常,原因還不太明瞭,不過已經找到了解決方法。

由於我們的伺服器資料有兩種型別,一種是xml(請求帶引數,即post方式),一種是json格式(請求引數直接附加在url後面,應該是get方式)。

之前請求這兩種資料都是用同一種方式獲取的即post方式,方法如下:

json資料地址為http://72.52.93.xxx/hdepg_data/dataForQuanQiuBo/2220143.js

/**
	 * post方式請求
	 * @param param			請求引數
	 * @param urlStr		請求地址
	 * @param contentType	內容格式
	 * @return
	 */
	public InputStream postMethod(String param, String urlStr,
			String contentType) {

		InputStream is = null;
		try {
			byte[] xmlData = param.getBytes("UTF-8");
			URL url = new URL(urlStr);
			URLConnection urlCon = url.openConnection();
			urlCon.setDoOutput(false);
			urlCon.setDoInput(true);
			urlCon.setConnectTimeout(40000);
			urlCon.setReadTimeout(40000);
			urlCon.setUseCaches(false);
			urlCon.setRequestProperty("Content-Type", contentType);
			urlCon.setRequestProperty("Content-length",
					String.valueOf(xmlData.length));
			DataOutputStream printout = new DataOutputStream(
					urlCon.getOutputStream());
			printout.write(xmlData);
			printout.flush();
			printout.close();
			is = urlCon.getInputStream();
		} catch (IOException e) {
			Log.e(TAG, "Url connection failed!");
			e.printStackTrace();
		} catch (Exception e) {
			Log.e(TAG, "Failed getting input stream!");
			e.printStackTrace();
		}
		return is;
	}

後來json資料換了一個地址:http://xxx.hanyastar.com/hdepg_data/dataForQuanQiuBo/xxxx.js,再用post方式請求資料的時候就出現java.io.FileNotFoundException異常了。感覺很奇怪,只是換了個地址而已,其他的操作都沒變,為什麼就不能成功訪問了呢?

後來上網查了下,發現有人如是說:

原文地址:http://www.mikebai.com/html/2012-03/939.html

最近把機器刷到4.0了
跑了一下自己的app,發現下載xml檔案部分丟擲異常:java.io.FileNotFoundException: http://www.jpfocus.com/xxxx.xml

可是在2.3的系統卻可以正常下載

我的程式碼:

URL url = new URL(urlstr);
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setRequestMethod("GET");
httpCon.setDoOutput(true);
httpCon.connect();

原因:
4.0中設定httpCon.setDoOutput(true),將導致請求以post方式提交,即使設定了httpCon.setRequestMethod("GET");
將程式碼中的httpCon.setDoOutput(true);刪除即可



關於setDoOutput(true)

網上查到的解釋是,設定true,表示你傳送的請求,會把body的內容傳送至server端,即POST和PUT才需要使用。GET完全可以不用設定。

難道新地址不支援post方式了?

於是我把請求方法修改了下:

public InputStream postMethodHanya(String param, String urlStr,
			String contentType) {

		InputStream is = null;
		try {
			byte[] xmlData = param.getBytes("UTF-8");
			URL url = new URL(urlStr);
			URLConnection urlCon = url.openConnection();
			urlCon.setDoOutput(false);
			urlCon.setDoInput(true);
			urlCon.setConnectTimeout(40000);
			urlCon.setReadTimeout(40000);
			urlCon.setUseCaches(false);
//			urlCon.setRequestProperty("Content-Type", contentType);
//			urlCon.setRequestProperty("Content-length",
//					String.valueOf(xmlData.length));
//			// urlCon.setFixedLengthStreamingMode(xmlData.length);
//			DataOutputStream printout = new DataOutputStream(
//					urlCon.getOutputStream());
//			printout.write(xmlData);
//			printout.flush();
//			printout.close();
			is = urlCon.getInputStream();
		} catch (IOException e) {
			Log.e(TAG, "Url connection failed!");
			e.printStackTrace();
		} catch (Exception e) {
			Log.e(TAG, "Failed getting input stream!");
			e.printStackTrace();
		}
		return is;
	}
註釋掉了post的body引數(如果不註釋,而setDoOutput又設定為false的時候會報: java.net.ProtocolException: method does not support a request body: GET),setDoOutput設定為false(或者註釋掉)。再用此方法獲取新地址json資料就成功了。

雖然用get方式獲取到了json資料,但是為什麼會有兩個地址的前後差異,現在還是沒弄明白,在這裡記錄下。如果有大神知道還請賜教。

ps:setDoInput和setDoOutput的含義

  1. publicvoid setDoInput(boolean doinput)將此 URLConnection 的 doInput 欄位的值設定為指定的值。    
  2. URL 連線可用於輸入和/或輸出。如果打算使用 URL 連線進行輸入,則將 DoInput 標誌設定為 true;如果不打算使用,則設定為 false。預設值為 true。  
  3. publicvoid setDoOutput(boolean dooutput)將此 URLConnection 的 doOutput 欄位的值設定為指定的值。    
  4. URL 連線可用於輸入和/或輸出。如果打算使用 URL 連線進行輸出,則將 DoOutput 標誌設定為 true;如果不打算使用,則設定為 false。預設值為 false。    
  1. httpUrlConnection.setDoOutput(true);以後就可以使用conn.getOutputStream().write()  
  2. httpUrlConnection.setDoInput(true);以後就可以使用conn.getInputStream().read();  
  3. get請求用不到conn.getOutputStream(),因為引數直接追加在地址後面,因此預設是false。  
  4. post請求(比如:檔案上傳)需要往服務區傳輸大量的資料,這些資料是放在http的body裡面的,因此需要在建立連線以後,往服務端寫資料。  
  5. 因為總是使用conn.getInputStream()獲取服務端的響應,因此預設值是true。