(解決 - 以下見註釋)HttpURLConnection的失敗在Android
我有一個實現多文件上傳的類。該代碼適用於除Android以外的每個我嘗試過的Java客戶端,並且這是我的Android應用中唯一的HTTP請求代碼,與我的後端服務無關。
連接responseCode是「-1」,所以在這裏進行一些非常討厭的事情。 Apache訪問或錯誤日誌中沒有任何條目出現,看起來好像請求永遠不會脫離android平臺。代碼正好通過連接寫入,但掛在連接讀取上,超時然後返回。行爲對於真實的手機和模擬器是相同的。
有沒有人知道在Android中發佈多部分文件時需要注意什麼問題?
我包括下面的類(輕微的衛生MODS的製作),所以你可以看到我到
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class GeoPictureUploader
{
static String serviceDomain = "http://staging.abaqus.net";
static String postUrl = serviceDomain + "/geo/upl/wupload/pictures";
static String CRLF = "\r\n";
static String twoHyphens = "--";
static String boundary = "*****mgd*****";
private String pictureFileName = null;
private String name = null;
private String password = null;
private DataOutputStream dataStream = null;
enum ReturnCode { noPicture, unknown, http201, http400, http401, http403, http404, http500};
public GeoPictureUploader(String name, String password)
{
this.name = name;
this.password = password;
}
public static void setServiceDomain(String domainName)
{
serviceDomain = domainName;
}
public static String getServiceDomain()
{
return serviceDomain;
}
public ReturnCode uploadPicture(String pictureFileName)
{
this.pictureFileName = pictureFileName;
File uploadFile = new File(pictureFileName);
if (uploadFile.exists())
try
{
FileInputStream fileInputStream = new FileInputStream(uploadFile);
URL connectURL = new URL(postUrl);
HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("User-Agent", "myGeodiary-V1");
conn.setRequestProperty("Connection","Keep-Alive");
conn.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
conn.connect();
dataStream = new DataOutputStream(conn.getOutputStream());
writeFormField("login", name);
writeFormField("password", password);
writeFileField("photo1", pictureFileName, "image/jpg", fileInputStream);
// final closing boundary line
dataStream.writeBytes(twoHyphens + boundary + twoHyphens + CRLF);
fileInputStream.close();
dataStream.flush();
dataStream.close();
dataStream = null;
String response = getResponse(conn);
int responseCode = conn.getResponseCode();
if (response.contains("uploaded successfully"))
return ReturnCode.http201;
else
// for now assume bad name/password
return ReturnCode.http401;
}
catch (MalformedURLException mue) {
// Log.e(Tag, "error: " + mue.getMessage(), mue);
System.out.println("GeoPictureUploader.uploadPicture: Malformed URL: " + mue.getMessage());
return ReturnCode.http400;
}
catch (IOException ioe) {
// Log.e(Tag, "error: " + ioe.getMessage(), ioe);
System.out.println("GeoPictureUploader.uploadPicture: IOE: " + ioe.getMessage());
return ReturnCode.http500;
}
catch (Exception e) {
// Log.e(Tag, "error: " + ioe.getMessage(), ioe);
System.out.println("GeoPictureUploader.uploadPicture: unknown: " + e.getMessage());
return ReturnCode.unknown;
}
else
{
return ReturnCode.noPicture;
}
}
/**
* @param conn
* @return
*/
private String getResponse(HttpURLConnection conn)
{
try
{
DataInputStream dis = new DataInputStream(conn.getInputStream());
byte [] data = new byte[1024];
int len = dis.read(data, 0, 1024);
dis.close();
int responseCode = conn.getResponseCode();
if (len > 0)
return new String(data, 0, len);
else
return "";
}
catch(Exception e)
{
System.out.println("GeoPictureUploader: biffed it getting HTTPResponse");
//Log.e(TAG, "GeoPictureUploader: biffed it getting HTTPResponse");
return "";
}
}
/**
* this mode of reading response no good either
*/
private String getResponseOrig(HttpURLConnection conn)
{
InputStream is = null;
try
{
is = conn.getInputStream();
// scoop up the reply from the server
int ch;
StringBuffer sb = new StringBuffer();
while((ch = is.read()) != -1) {
sb.append((char)ch);
}
return sb.toString(); // TODO Auto-generated method stub
}
catch(Exception e)
{
System.out.println("GeoPictureUploader: biffed it getting HTTPResponse");
//Log.e(TAG, "GeoPictureUploader: biffed it getting HTTPResponse");
}
finally
{
try {
if (is != null)
is.close();
} catch (Exception e) {}
}
return "";
}
/**
* write one form field to dataSream
* @param fieldName
* @param fieldValue
*/
private void writeFormField(String fieldName, String fieldValue)
{
try
{
dataStream.writeBytes(twoHyphens + boundary + CRLF);
dataStream.writeBytes("Content-Disposition: form-data; name=\"" + fieldName + "\"" + CRLF);
dataStream.writeBytes(CRLF);
dataStream.writeBytes(fieldValue);
dataStream.writeBytes(CRLF);
}
catch(Exception e)
{
System.out.println("GeoPictureUploader.writeFormField: got: " + e.getMessage());
//Log.e(TAG, "GeoPictureUploader.writeFormField: got: " + e.getMessage());
}
}
/**
* write one file field to dataSream
* @param fieldName - name of file field
* @param fieldValue - file name
* @param type - mime type
* @param fileInputStream - stream of bytes that get sent up
*/
private void writeFileField(
String fieldName,
String fieldValue,
String type,
FileInputStream fis)
{
try
{
// opening boundary line
dataStream.writeBytes(twoHyphens + boundary + CRLF);
dataStream.writeBytes("Content-Disposition: form-data; name=\""
+ fieldName
+ "\";filename=\""
+ fieldValue
+ "\""
+ CRLF);
dataStream.writeBytes("Content-Type: " + type + CRLF);
dataStream.writeBytes(CRLF);
// create a buffer of maximum size
int bytesAvailable = fis.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fis.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
dataStream.write(buffer, 0, bufferSize);
bytesAvailable = fis.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fis.read(buffer, 0, bufferSize);
}
// closing CRLF
dataStream.writeBytes(CRLF);
}
catch(Exception e)
{
System.out.println("GeoPictureUploader.writeFormField: got: " + e.getMessage());
//Log.e(TAG, "GeoPictureUploader.writeFormField: got: " + e.getMessage());
}
}
/**
* @param args
*/
public static void main(String[] args)
{
if (args.length >= 0)
{
GeoPictureUploader gpu = new GeoPictureUploader("john", "notmyrealpassword");
String picName = args[0];
ReturnCode rc = gpu.uploadPicture(picName);
System.out.printf("done");
}
}
}
幾個小時的調試後,它原來是我們的路由器中的錯誤,由於某種原因或其他掛在出站往返回到我們分期服務器當消息超過幾個k字節時。我一直在開發使用無線網絡連接的手機,當然仿真器也使用網絡。一旦我們瞄準了我們的生產服務器,它就立即開始工Cellular也很好。 – jottos 2009-07-14 10:04:30
大家請隨意使用這個Android multipart/form-data類。它像一個冠軍。並且很容易推廣到通用的多部分/表單數據類。 對代碼的清理提示 - 您可以刪除getResponse()方法,轉而使用 HttpURLConnection方法conn.getResponseMethod(),當然也可以使用conn.getResponseCode()來獲取正確的http服務器代碼 – jottos 2009-07-14 10:05:27