はじめまして、がびょうといいます。
Indy10のTIdHTTPについてですが、
HTTP:=TIdHTTP.Create(nil);
HTTP.Get('http://yahoo.co.jp/');
とやると、
'日付に変換できない値が渡されました'
とエラーが出ます。
http://www.yahoo.co.jp/
でも同じエラーが出ます。Yahoo!以外ならエラーは出ません。
同じようなエラーが出たことがある方はどのようにして解決したかをお教えいただきたいです。
よろしくおねがいします。
Indy9では、そんなエラーは出ないけど、
Yahooのページのヘッダーに
Expires:-1
が含まれているのが原因かな…
よくわかんねーけど
IEで保存してからコード見ると<!--京-->ってかいてある部分、自分でデコードするときアソコが引っかかってエラーがおこんだ。
何であんな文字を入れる理由があんだ?
こえー世の中だな。
>何であんな文字を入れる理由があんだ?
ソースがEUCコードで書かれているページには、文字化けを防止するために
<!-- 美乳 -->
をソースコードに入れておくことがよく行われるようで、
<!--京-->
にも同様の効果があるんでしょうね。
さすがにYAHOOは「美乳」を使うのは差し控えたのでは。
そうなんですか...美乳ですか。
解決方法はないんですか?
というか、try〜exceptで無視してもいいんでしょうか?
ハチ: 「日付の変換エラー出るンは、Yahooがアカンの?」
クマ: 「そや、ヘッダーの Expiresフィールド値が-1になってるのが原因やで」
ハチ: 「Indy、ヘボちゃうン?」
クマ: 「-1は'想定外'ちゅうことや」
ハチ: 「ん?そいや、去年'想定内'が流行語やったな〜」
クマ: 「Indy10、空の時刻値には対応したんやけど、-1はアカン」
ハチ: 「ンなら、どないしたらエエん?」
クマ: 「IdGlobalProtocols.pasの GMTToLocalDateTime関数、こう書き換えてや」
//if s = '' then // 空文字の場合には対応してる
if (s = '')or(s = '-1') then // '-1'の場合にも対応させる
begin
result := 0;
end
else
begin
Result := RawStrInternetToDateTime(S);
.....
ハチ: 「ドコやったかいな〜'Expires: 0'ちゅうンもあるで。コレどや?」
クマ: 「うっ、それも'想定外'」
IdGlobalProtocols.pasを修正して、Indyを再コンパイル&再インストールしたんですが、直りません。
ブレークポイントを設定してTRACEしてみたら?
GMTToLocalDateTimeの
if s = '' then
の前に
MessageBox(0,PChar(s),'',0);
をつけてコンパイルしてみたんですが、ダイアログが出ません。
ということは、コンパイルできてない?それか関数が呼ばれていないんだと思うんですが。
IdGlobalProtocols.pas
IdCompilerDefines.inc
などを自分のプロジェクトのフォルダに入れてコンパイルすること。
やってみました。が、結果は同じです。
コンパイルは出来ているみたいです。
ブレークポイントは設定してみたの?
設定してます
自分のプロジェクトにコピーしたGIdGlobalProtocols.pasのGMTToLocalDateTime関数にブレークポイントを設定して IdHTTPのGetを実行すれば、ブレークポイントで停止するはず。そのブレークポイントは有効になってる?
そのフォルダ内にGIdGlobalProtocols.dcuファイルは出来てる?
*.dcuはあります。
あと、ブレークポイントを設定して実行するとうまく出来ますが、はずして実行すると例外が発生します。
IdGlobalProtocols.pasの GMTToLocalDateTime関数の最初の行、
if s = '' then // 空文字だけに対応
ここにプレークポイント設定すると、IdHttp.Get('http://yahoo.co.jp/')の実行で3回停止する。
1回目の sの値は、'Fri,20 Jan 2006 **:**:** GMT'
2回目の sの値は、空文字
3回目の sの値は、'-1'
3回目で EConvertError例外(日付の変換エラー)が発生するので、その行を
if (s = '')or(s = '-1') then // '-1'の場合にも対応
に書き換えて実行すれば、その例外は出なくなる。
※ それでも EIdConnClosedGracefully 'Connection Closed Gracefully'が出るのは、Indyの「お約束」。
-1と0の対策はしました。
たぶんそのお約束の例外です。でてるのは。
解決...かと思ったんですが、Yahoo!カテゴリのどれかをクリックすると
EIdHTTPProtocolException
が発生します。
IdHttp.pasの ProcessResponse関数内にブレークポイントを設定してみたら?
久しぶりの投稿です。本題とは外れますが、HTTPのクライアントざっと作ってみました。一応<!-- 美乳 -->や<!--京-->問題を避けられるデコード関数もつけました。
どうしてもIndyがいいというなら虫してください。
unit HTTPClient;
interface
uses
Classes, Sockets, SysUtils;
type
TMyHTTP = class(TCustomIpClient)
property Active;
property BlockMode;
property Connected;
property RemoteHost;
property RemotePort;
property OnCreateHandle;
property OnDestroyHandle;
property OnConnect;
property OnDisconnect;
property OnReceive;
property OnSend;
property OnError;
protected
FHeader: string;
function SetHeaderAnswerBody(re: string): string;
public
property Header: string read FHeader;
constructor Create(AOwner: TComponent); override;
//function Head(url: string): string;
function Get(url: string): string;
//function Post(url: string; dat: string): string;
end;
procedure AnalyzeURL(const url: string; var domain: string; var path: string; var param: string; var port: string);
var
g_LastURL : string = '';
g_LastDomain: string = '';
g_LastPath: string = '';
g_LastParam: string = '';
g_LastPort: string = '';
function euc2sjis(euc: string): string;
implementation
function euc2sjis(euc: string): string;
var
i, len: integer;
w: word;
h, eucHi, k, l, m, eucLow, eucw: word;
begin
result := '';
len := Length(euc);
if len = 0 then exit;
i := 1;
while i <= len do begin
h := byte(euc[i]);
case h of
$A1..$FE: begin
//--------------------
l := byte(euc[i + 1]);
eucw := h shl 8 + l;
case h of
$F9..$FF: begin
case eucw of
$F9A0..$F9C3: w := eucw + $BB;
$F9C4..$F9FF: w := eucw + $BC;
$FAA0..$FAE2: w := eucw + $1A;
$FAE3..$FAFE: w := eucw + $5D;
$FAFF..$FBA0: w := eucw + $4E;
$FBA1..$FBFF: w := eucw - $45;
$FCA1..$FCE2: w := eucw - $E6;
$FCF1..$FCFA: w := eucw - $2B1;
$FCE3..$FCEE: w := eucw - $A3;
$FCFC..$FCFF: w := eucw - $2A7;
else begin
w := $8145;
end;
end;
result := result + char(w shr 8) + char(w and $FF);
end;
else begin
case h of
0..$DE: begin
k := h - $A1;//3F
eucHi := $81 + k shr 1;
end;
else begin
k := h - $DF;
eucHi := $E0 + k shr 1;
end;
end;
l := (eucw and $FF) - $A0;
m := l shr 4;
case k mod 2 of
0: begin
case m of
0: eucLow := $3F + l and $F;
1: eucLow := $4F + l and $F;
2: eucLow := $5F + l and $F;
3: eucLow := $6F + l and $F;
4: eucLow := $80 + l and $F;
5: eucLow := $90 + l and $F;
end;
end;
1: begin
case m of
0: eucLow := $9E + l and $F;
1: eucLow := $AE + l and $F;
2: eucLow := $BE + l and $F;
3: eucLow := $CE + l and $F;
4: eucLow := $DE + l and $F;
5: eucLow := $EE + l and $F;
end;
end;
end;
result := result + char(eucHi) + char(eucLow);
end;
end;
//--------------------
inc(i, 2);
end;
else begin
case h of
$8E: begin
if (i + 1) <= len then begin
result := result + euc[i + 1];
end;
inc(i, 2);
end;
else begin
result := result + char(h);
inc(i);
end;
end;
end;
end;
end;
end;
function TMyHTTP.SetHeaderAnswerBody(re: string): string;
var
idx: integer;
begin
idx := pos(#$D#$A + #$D#$A, re);
FHeader := Copy(re, 1, idx - 1);
result := Copy(re, idx + 2, Length(re));
end;
procedure AnalyzeURL(const url: string; var domain: string; var path: string; var param: string; var port: string);
var
aurl: string;
idx, idx2: integer;
s, t: string;
begin
idx := pos('://', url);
case idx of
2..7: begin
s := trim(Copy(url, 1, idx - 1));
if s = 'http' then begin
port := '80';
end
else begin
if s = 'https' then begin
port := '443';
end;
end;
end;
end;
idx := pos(s+'://', url);
case idx of
0: begin
aurl := trim(url);
end;
1: begin
aurl := trim(Copy(url, idx + Length(s) + 3, Length(url)))
end;
else begin
aurl := trim(url);
end;
end;
idx := pos('?', aurl);
case idx of
0: begin
param := '';
end;
else begin
param := Copy(aurl, idx + 1, Length(aurl));
aurl := Copy(aurl, 1, idx - 1);
end;
end;
idx := pos('/', aurl);
case idx of
0: begin
domain := aurl;
path := '/';
end;
else begin
domain := Copy(aurl, 1, idx - 1);
path := Copy(aurl, idx, Length(aurl));
end;
end;
idx := pos(':', domain);
case idx of
0:;
else begin
domain := Copy(domain, 1, idx - 1);
end;
end;
s := Copy(domain, 1, 1);
if (s = '') or (s = '.') then begin
s := StringReplace(g_LastPath, '/', '\', [rfReplaceAll]);
t := ExtractFileName(s);
t := Copy(s, 1, Length(s) - Length(t));
path := StringReplace(t, '\', '/', [rfReplaceAll]) + domain + path;
domain := g_LastDomain;
end;
g_LastURL := url;
g_LastDomain := domain;
g_LastPath := path;
g_LastParam := param;
g_LastPort := port;
end;
constructor TMyHTTP.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
RemotePort := '80';
BlockMode := bmBlocking;//bmNonBlocking;
end;
function TMyHTTP.Get(url: string): string;
var
domain, path, param: string;
rq, re: string;
buf: array[0..1023] of char;
len: integer;
port: string;
begin
AnalyzeURL(url, domain, path, param, port);
if pos(domain + ':8080', url) > 0 then port := '8080';
RemoteHost := domain;
RemotePort := port;
if param <> '' then begin
rq := 'GET ' + path + '?' + param + ' HTTP/1.0' + #$D#$A + #$D#$A;
end
else begin
rq := 'GET ' + path + ' HTTP/1.0' + #$D#$A + #$D#$A;
end;
re := '';
Active := true;
try
SendBuf(rq[1], Length(rq));
len := ReceiveBuf(buf, 1024);
while len > 0 do begin
re := re + Copy(buf, 1, len);
len := ReceiveBuf(buf, 1024);
end;
finally
Active := false;
end;
re := euc2sjis(re);
result := SetHeaderAnswerBody(re);
end;
end.
>IdHttp.pasの ProcessResponse関数内にブレークポイントを設定してみたら?
ブレークポイントを設定しても、ブレークポイントの位置にたどり着く前にお約束の例外が出てしまいます。
>HTTPClient
Sockets.dcuが見つかりません...
>>HTTPClient
>Sockets.dcuが見つかりません...
Socketsユニットは、D6 Personal版には無いですね。
>ブレークポイントを設定しても、ブレークポイントの位置にたどり着く前にお約束の例外が出てしまいます。
ブレークポイントが有効になっていれば、そんなことはないけど。
コピーしたIdHttp.pasはコンパイルされている?
>ブレークポイントが有効になっていれば、そんなことはないけど。
>コピーしたIdHttp.pasはコンパイルされている?
コンパイルされてます。
>もしかして、Personal?
D6 Personalです。
ブレークポイントを設定しなかったら、どこで止まる?
えーと、IdIOHandler.pasのTIdIOHandler.RaiseConnClosedGracefullyで、例外は`Connection Closed Gracefully`です。
Yahoo!にアクセスしただけで例外が出ます。
ということは、
EIdHTTPProtocolException例外は出ないの?
>解決...かと思ったんですが、Yahoo!カテゴリのどれかをクリックすると
>EIdHTTPProtocolException
>が発生します。
この問題はどうなったのかな?
デバッグ時には`Connection Closed Gracefully`が出るのでEIdTHHTPProtocolExceptionは出ません。
デバッグ時以外は`Connection Closed Gracefully`がでないのでEIdHTTPProtocolExceptionがでます。
おかしいな、どのURLを指定してるんだろ?
どのカテゴリ(例えば'http://yahoo.co.jp/r/cet')を選んでも、
EIdTHHTPProtocolException例外が出るけど…
http://yahoo.co.jp/r/cetだと`HTTP/1.0 302 Found`です。
EIdTHHTPProtocolException例外。
ステータスコード=302ならば、Locationヘッダに書かれているURLにリダイレクトすべきです。
EIdHTTPProtocolExceptionの説明には、「HTTP応答から予期しないHTTP数値応答コードを受け取った場合に生成される」とかかれていますが、RFCには302が定義されているので予期しないのはおかしいですね。
302などのステータスコードに関しては、RFC2068あたりを参照してください。
追記。おかしいのはIdHTTPの実装です。
「実行環境によって異なるのはおかしい」という意味ではないです。IdHTTP自体が、302を考慮していないのでしょう。
解決策はないんでしょうか?
でるふぁい: 「自分、Redirectに対応したンいつやったかいな?」
いんでぃ10: 「2000年の初夏やったな〜、オヤジのいんでぃ9からやろ」
でるふぁい: 「もう4年も過ぎとるで、エエかげんデフォルトで飛ばんかい」
いんでぃ10: 「飛ばんのは、おれンちの主義や」
でるふぁい: 「ンなら、実力行使や。IdHttp.pasの365行目のId_TIdHTTP_HandleRedirects、Trueに書き換えたる」
いんでぃ10: 「そないな荒療治せんで、HandleRedirectsぷろぱてぃ、Trueにしといたらエエやン」
でるふぁい: 「デフォルトで飛ばんオマエの根性、気にくわんのや」
いんでぃ10: 「ナニ言うても、主義は変えへんで」
でるふぁい: 「おいおい、仕様はコロコロ変えとるやんか」
いんでぃ10: 「それも、おれンちの主義や。文句あっか?」
無事解決しました。
協力してくださった方々、本当にありがとうございました。
ツイート | ![]() |