레이블이 HttpGet인 게시물을 표시합니다. 모든 게시물 표시
레이블이 HttpGet인 게시물을 표시합니다. 모든 게시물 표시

2009년 5월 21일 목요일

org.apache.http.client.ClientProtocolException on Android

Android 개발시 apache http client 모듈을 이용할 경우 HttpClient 클래스를 이용하여 다음과 같이 GET/POST 메소드로 전송할 수 있다. 즉, HTTP로 요청할 수 있다.
일단 간단한 소스 코드를 살펴보자.

HttpClient client = new DefaultHttpClient();
HttpGet method = new HttpGet("http://www.daum.net");

method.setHeader("User-Agent", "Android emulator");

HttpResponse res = null;
try {
res = client.execute(method);
StatusLine status = res.getStatusLine();
if (status.getStatusCode() == HttpStatus.SC_OK) {
System.out.println("Method completed");
} else {
System.err.println("Method failed: " + status.getReasonPhrase());
}
}  catch ( ClientProtocolException e ) {
        // TODO Auto-generated catch block
        e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
}

일단, 위의 소스는 에러가 발생하지 않는다. 왜냐하면 HttpGet 클래스를 이용한 GET 메소드로 요청하는 것이기 때문이다.
따라서 별도의 Content-Length를 명시하지 않아도 된다.

그런데, 만약 POST 메소드로 요청시에는 Http body 가 첨부됨으로 Content-Length 를 http header 에 명시해 준다. 안드로이드 상에서는 다음과 같이 해 주면 된다.

method.setHeader("Content-Length", "" + httpBody.length);

여기서 이 코딩이 화근이다. 실제로 안드로이드 버전이 아닌 자바 버전의 아파치 HttpComponents를 이용할 경우에는 POST로의 요청일 경우에도 위의 코드를 넣어줄 경우에는 에러가 발생하지 않는다.
하지만, 안드로이드 애플리케이션에서 다음과 같이 http body 를 넣어줄 수 있는데, 여기서 위의 코드와 같이 Content-Length 를 명시할 경우 ClientProtocolException 이 발생한다.

byte[] httpBody = "Android http body".getByte();
HttpEntity entity = new ByteArrayEntity(httpBody);

HttpGet method = new HttpGet("http://test.wiseant.net/debugger");
method.setHeader("Content-Length", "" + httpBody.length);


05-22 06:40:56.533: WARN/System.err(1030): org.apache.http.client.ClientProtocolException

따라서 실제코드 상에서는 Content-Length 를 명시하는 setHeader 메소드를 사용하지 않아야 한다.
자바 버전의 HttpComponents 를 사용하는 것과 안드로이드의 Http client 컴포넌트를 사용하는 것은 상당 부분 차이가 난다.
흠... 이 버그 찾는데 오후 내도록 찾은 것이니 아깝진 하다... 쩝...^^;;