Does anyone know how to process 404 page contents using #Indy ? After receiving the 404 response, I can't access the Contentstream.

Does anyone know how to process 404 page contents using #Indy ?  After receiving the 404 response, I can't access the Contentstream.

Response.ContentLength <> Response.ContentStream.Size

Comments

  1. Not sure. The last time I did HTTP with Delphi was using these wrappers, but not with any negative error handling as it was proof of concept state: https://bitbucket.org/jeroenp/besharp.net/commits/0b051f59a2834c5ab5280bcbad23c26203eccfab (final implementation was C# because of various reasons).

    ReplyDelete
  2. Yes, but don't have code to hand. Will try to get back to you...

    ReplyDelete
  3. Walter Prins that would be great. The only ugly solution I found so far is to catch EIdHTTPProtocolException where Errormessage contains the response pages body.
    The problem is that I'm trying to consume a REST/JSON service, where the body can contain different errorcodes, e.g.:
    {
      "errorCode" : 404,
      "errorDescription" : "Resource not found."
    }

    ReplyDelete
  4. Oliver Funcke​ that was the part of the reason to move this piece to C#. JSON is a piece of cake there and it just works.

    ReplyDelete
  5. Jeroen Wiert Pluimers C# is no option in this case.

    ReplyDelete
  6. There are alternatives to Indy, e.g. the new HTTP client introduced with XE8, or classes, like our Open source SynCrtSock.pas unit, which allows raw socket, WinHttp or WinINet access. https://github.com/synopse/mORMot/blob/master/SynCrtSock.pas
    Also consider alternatives for JSON process, if you are using the DBXJson.pas official unit, which is just slow and difficult to work with.

    ReplyDelete
  7. Sorry I finally had a look at the code I was thinking of.  I'd forgotten about the irritating way Indy handled HTTP non-success response codes...  

    But to answer your question, basically in the case of error, you can get what would've normally been in the contentstream from the ExceptionObj.ErrorMessage property.  So you can use something like the following if you want to get the content response regardless of http response code (untested):

    var 
      FResponseStream: TStringStream;
      FRequestURL, Content : String;
    begin
      //.... etc etc
      try
        FIdHTTP.Get(FRequestURL, FResponseStream);
        Content := FResponseStream.DataString;
      except
        on E:EIdHTTPProtocolException do
          Content := E.ErrorMessage; 
      end;
      // At this point, "Content" contains the response body, both for 
      // successful (200) as well as other response codes.
      
      //.... etc etc
    end;

    Please note, the above obviously squashes the error/error code details/exception and is therefore likely not actually how you'd want to do it in reality - presumably interpreting a (JSON?) error body would be handled by different code in the client from the "200 success" happy path -- in that case re-raising the exception, or raising a different "local" exception that signals that something went wrong and that would be caught by some suitable handling code somewhere else would be one way to deal with it. 

    Let me know if this doesn't help and/or I've misunderstood your problem.

    ReplyDelete
  8. Walter Prins thanks, that was the solution I mentioned as ugly in my follow-up post.

    try
        FResponse := FClient.Get(FURI);
        Result      := True;
      except
        on E: EIdHTTPProtocolException do
        begin
          FResponse := EIdHTTPProtocolException(E).ErrorMessage;
        end;
      end;

    ReplyDelete
  9. hoNoProtocolErrorException and array of error codes do basically the same. No exception is raised and the input stream gets lost in case of 404. The only way really seems to let the exception raise and get the data from its errormessage field.

    ReplyDelete
  10. Must say that behaviour seems kind of illogical.  If one's explicitly telling Indy to NOT raise an exception, then you'd expect Indy to then just return everything retrieved, including content... As-is, hoNoProtocolErrorException & friends usefulness seems rather limited then -- I wonder if this behaviour is really intentional or whether this is worth a bug report?

    ReplyDelete
  11. It's a problem whitin the ProcessResponse / Checkexception, setting the Response.ContentStream back to the state before it had been read.

    ReplyDelete

Post a Comment