2010.01.25 추가
오늘자로 아래와 같이 코드에 추가된 내용이 있습니다. (아래 코드에는 반영함)
먼저, IdHTTP1.Request.ContentType에 ‘application/x-www-form-urlencoded’ 값을 넣어주는 라인이 추가되었구요. (이 라인이 없으면 제대로 HTML 폼에 POST로 전송된 것으로 인식되지 못하는데, IdHTTP에서 왜 추가해주지 않았는지 이해가 안되네요)
다음으로, POST를 한 후 결과 값을 받아와서 문자열의 길이를 스트림의 크기만큼으로 설정해준 부분이 추가되었습니다. (이게 없어서 문자열 끝 뒤에 쓰레기 값이 넘어오는 경우가 있더군요)
——————————————————————-
저번 글에 이어, 2009/2010 버전에 번들된 Indy의 한글 깨짐 문제에 대해 계속 알아보겠습니다. 이번에 알아볼 것은, idHTTP에서 Post를 했을 때 웹 서버로 전달된 컨텐트 내용의 한글 부분이 깨지는 문제입니다.
다음은 2009 버전에 번들된 Indy의 idHTTP 소스에서 오버로드된 여러 Post 메소드들입니다.
1 2 3 4 5 6 |
function Post(AURL: string; ASource: TStrings): string; overload; function Post(AURL: string; ASource: TStream): string; overload; function Post(AURL: string; ASource: TIdMultiPartFormDataStream): string; overload; procedure Post(AURL: string; ASource: TIdMultiPartFormDataStream; AResponseContent: TStream); overload; procedure Post(AURL: string; ASource: TStrings; AResponseContent: TStream); overload; procedure Post(AURL: string; ASource, AResponseContent: TStream); overload; |
여러가지로 테스트를 해봤는데, 이 중에서 idHTTP에서 Post로 전송한 데이터의 한글이 깨지는 문제는 Post 데이터인 ASource 파라미터로 TStrings 타입을 넘기는 경우에만 발생하는 것으로 보입니다. 다시 말해 ASource로 TStream 타입을 넘기는 경우에는 발생하지 않습니다.
역시 charset, 즉 인코딩의 처리 문제이구요.
실제 idHTTP의 소스를 보면, 2009에 번들된 Indy 버전에서는 인코딩 처리가 아주 잘못되어 있고, 2010 번들 버전은 많이 개선되었으나 아직 문제가 있습니다.
어쨌든, TStringList 등 TStrings 클래스로 넘기던 코드에서 한글 문제가 발생했다면, 그것을 TStringStream으로 다시 쓴 다음 Post를 하면 됩니다.
그런데, Post로 데이터를 넘긴 후에도 데이터를 다시 받아야 하는 경우가 종종 있습니다. 따라서 앞서의 Get 방법을 다룬 포스트의 코드와 같은 방식으로 처리해야 합니다. 코드는 아래와 같습니다.
Delphi 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
var rbstr: RawByteString; HTML: String; MemoryStream: TMemoryStream; StringStream: TStringStream; slPost: TStringList; begin slPost := TStringList.Create; slPost.Add('student_info=박지훈'); slPost.Add('reserve_purpose=임프'); StringStream := TStringStream.Create(slPost.Text); slPost.Free; MemoryStream := TMemoryStream.Create; IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded'; IdHTTP1.Post('http://주소', StringStream, MemoryStream); StringStream.Free; SetLength(rbstr, MemoryStream.Size); StrLCopy(PAnsiChar(rbstr), PAnsiChar(MemoryStream.Memory), MemoryStream.Size); MemoryStream.Free; if Pos('utf-8', IdHTTP1.Response.ContentType)=0 then SetCodePage(rbstr, 949, false) else SetCodePage(rbstr, 65001, false); Memo1.Lines.Text := rbstr; end; |
C++Builder 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
TStringList *slPost = new TStringList; slPost->Add("student_info=박지훈"); slPost->Add("reserve_purpose=임프"); TStringStream *StringStream = new TStringStream(slPost->Text); delete slPost; TMemoryStream *MemoryStream = new TMemoryStream; IdHTTP1->Request->ContentType = "application/x-www-form-urlencoded"; IdHTTP1->Post("http://주소", StringStream, MemoryStream); delete StringStream; RawByteString rbstr; rbstr.SetLength(MemoryStream.Size); strncpy(rbstr.c_str(), (char *)(MemoryStream->Memory), MemoryStream->Size); delete MemoryStream; if(Pos("utf-8", IdHTTP1->Response->ContentType)==0) SetCodePage(rbstr, 949, false); else SetCodePage(rbstr, 65001, false); String HTML = rbstr; |
저번에도 말씀드렸다시피 2009/2010 버전에 번들된 Indy의 한글 깨짐 문제는 여기저기 꽤 복잡하고 원인도 몇군데 되기 때문에, 이걸로 끝난 것이 아닙니다. 다음에는 idTCP 컴포넌트들과 idFTP 컴포넌트 쪽으로도 살펴보고, 그에 대한 해결책도 알아볼 거구요. 근본적으로는, 이 모든 회피 방법들을 종합하여 번들된 Indy 자체를 완전히 패치하는 방법도 알려드릴 것입니다.
좋은 포스팅 감사합니다.
소스에서
slPost.Add(”student_info=박지훈”);
slPost.Add(”reserve_purpose=임프”);
부분은
slPost.Add(”&student_info=박지훈”);
slPost.Add(”&reserve_purpose=임프”);
이렇게 바꿔야 서버측(ASP.NET)
에서 항목별로 파싱이 제대로 되는 것 같습니다.
정말 도움이 많이 되었습니다.
euc-kr 로만 받는 서버가 있어서 ㅠㅠ
제 경우는 이렇게 해결했습니다.
PostData := TStringStream.Create(AnsiString(‘str=블라블라’));
IdHTTP1.Post(‘서버주소’,PostData);
TStringList 에 한글 문자열을 AnsiString 으로 변환해서 넣으니 IdHTTP에서 뭔가 이상한 짓을 하나 봅니다.