2

私のDelphi2010アプリはマルチスレッドを使用してコンテンツをアップロードし、アップロードされたデータはログインが必要なPHP / WebアプリケーションにPOSTされるため、TIdCookieManagerはスレッドではないため、共有/グローバルCookieマネージャー( Indy10リビジョン4743を使用)を使用する必要があります-安全な :(

また、サーバー側では、セッションIDが5分ごとに自動的に再生成されるため、グローバルCookieマネージャーとローカルCookieマネージャーの両方を同期させる必要があります。

私のコードは次のようになります。

TUploadThread = class(TThread)
// ...

var
   GlobalCookieManager : TIdCookieManager;

procedure TUploadThread.Upload(FileName : String);
var
   IdHTTP           : TIdHTTP;
   TheSSL           : TIdSSLIOHandlerSocketOpenSSL;
   TheCompressor    : TIdCompressorZLib;
   TheCookieManager : TIdCookieManager;
   AStream          : TIdMultipartFormDataStream;
begin
     ACookieManager := TIdCookieManager.Create(IdHTTP);

     // Automatically sync cookies between local & global Cookie managers
     @TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
     begin
          OmniLock.Acquire;
          try
             GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
          finally
                  OmniLock.Release;
          end;    // try/finally

          VAccept := True;
     end )^ ) + $0C)^;
     // ======================================== //


     IdHTTP         := TIdHTTP.Create(nil);
     with IdHTTP do
     begin
          HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv];
          AllowCookies    := True;
          HandleRedirects := True;
          ProtocolVersion := pv1_1;

          IOHandler       := TheSSL;
          Compressor      := TheCompressor;
          CookieManager   := TheCookieManager;
     end;    // with

     OmniLock.Acquire;
     try
        // Load login info/cookies
        TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection);
     finally
            OmniLock.Release;
     end;    // try/finally

     AStream         := TIdMultipartFormDataStream.Create;

     with Stream.AddFile('file_name', FileName, 'application/octet-stream') do
     begin
          HeaderCharset  := 'utf-8';
          HeaderEncoding := '8';
     end;    // with

     IdHTTP.Post('https://www.domain.com/post.php', AStream);
     AStream.Free;
end;

しかし、それは機能しません!AddCookies()を呼び出すと、この例外が発生します

プロジェクトMyEXE.exeは、メッセージ「アドレス00000000でのアクセス違反。アドレス00000000の読み取り」で例外クラスEAccessViolationを発生させました。

また、assign()を使用してみました。

 TheCookieManager.CookieCollection.Assign(GlobalCookieManager.CookieCollection);

しかし、私はまだ同じ例外を受け取ります、通常ここで:

 TIdCookieManager.GenerateClientCookies()

誰もがこれを修正する方法を知っていますか?

4

3 に答える 3

5

OnNewCookieイベントに匿名の手順を使用しないでください。代わりに通常のクラスメソッドを使用してください。

procedure TUploadThread.NewCookie(ASender: TObject; ACookie : TIdCookie; var VAccept : Boolean);
var
  LCookie: TIdCookie;
begin
  LCookie := TIdCookieClass(ACookie.ClassType).Create;
  LCookie.Assign(ACookie);
  OmniLock.Acquire; 
  try 
    GlobalCookieManager.CookieCollection.AddCookie(LCookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL); 
  finally 
    OmniLock.Release; 
  end;
  VAccept := True;
end;

または:

procedure TUploadThread.NewCookie(ASender: TObject; ACookie : TIdCookie; var VAccept : Boolean);
begin
  OmniLock.Acquire; 
  try 
    GlobalCookieManager.CookieCollection.AddServerCookie(ACookie.ServerCookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL); 
  finally 
    OmniLock.Release; 
  end;
  VAccept := True;
end;

次に、次のように使用します。

procedure TUploadThread.Upload(FileName : String); 
var 
  IdHTTP           : TIdHTTP; 
  TheSSL           : TIdSSLIOHandlerSocketOpenSSL; 
  TheCompressor    : TIdCompressorZLib; 
  TheCookieManager : TIdCookieManager; 
  TheStream        : TIdMultipartFormDataStream; 
begin 
  IdHTTP := TIdHTTP.Create(nil); 
  try
    ...
    TheCookieManager := TIdCookieManager.Create(IdHTTP); 
    TheCookieManager.OnNewCookie := NewCookie;

    with IdHTTP do 
    begin 
      HTTPOptions     := [hoForceEncodeParams, hoNoParseMetaHTTPEquiv]; 
      AllowCookies    := True; 
      HandleRedirects := True; 
      ProtocolVersion := pv1_1; 

      IOHandler       := TheSSL; 
      Compressor      := TheCompressor; 
      CookieManager   := TheCookieManager; 
    end;    // with 

    OmniLock.Acquire; 
    try 
      // Load login info/cookies 
      TheCookieManager.CookieCollection.AddCookies(GlobalCookieManager.CookieCollection); 
    finally 
      OmniLock.Release; 
    end;

    TheStream := TIdMultipartFormDataStream.Create; 
    try
      with TheStream.AddFile('file_name', FileName, 'application/octet-stream') do 
      begin 
        HeaderCharset  := 'utf-8'; 
        HeaderEncoding := '8'; 
      end;

      IdHTTP.Post('https://www.domain.com/post.php', TheStream); 
    finally
      TheStream.Free; 
    end;
  finally
    IdHTTP.Free;
  end;
end; 
于 2012-05-03T21:51:40.660 に答える
3

私が推測しなければならなかったとしたら、あなたの問題はここのどこかにあると思います:

 // Automatically sync cookies between local & global Cookie managers
 @TheCookieManager.OnNewCookie := pPointer(Cardinal(pPointer( procedure(ASender : TObject; ACookie : TIdCookie; var VAccept : Boolean)
 begin
      OmniLock.Acquire;
      try
         GlobalCookieManager.CookieCollection.AddCookie(ACookie, TIdHTTP(TIdCookieManager(ASender).Owner).URL{IdHTTP.URL});
      finally
              OmniLock.Release;
      end;    // try/finally

      VAccept := True;
 end )^ ) + $0C)^;

マジックナンバーが何の$0Cためにあるのかはわかりませんが、コンパイラーにこれを受け入れさせるのにかなりの時間がかかったので、それらのキャストはすべてそこにあるに違いありません。あるものを別のものに割り当てることができなかったというタイプエラーが発生しました。

これらのタイプエラーには理由があります。型システムをハックすると、物事が壊れる可能性が非常に高くなります。その匿名メソッドをTUploadThreadで通常のメソッドに変えて、そのように割り当ててみて、うまく機能しないかどうかを確認してください。

于 2012-05-03T21:40:56.823 に答える
2

コメントへの返信:

ありがとうございます。通常のメソッドに変換しましたが、AddCookies()で例外が発生します。最後の例外は、FRWLock.BeginWriteを読み取る行で発生しました。この手順では、TIdCookies.LockCookieList(AAccessType:TIdCookieAccess):TIdCookieList;

エラーがでのアクセス違反である場合Read of address 00000000、それは非常に具体的な意味を持っています。これは、 nilのオブジェクトで何かをしようとしていることを意味します。

それを取得したら、デバッガーに移動します。エラーが発生していると言った行でエラーが発生している場合は、この時点でSelfまたFRWLockはがゼロであることがほぼ確実です。両方の変数をチェックして、どちらがまだ構築されていないかを把握してください。そうすれば、解決策がわかります。

于 2012-05-03T22:15:19.117 に答える