Delphi HTTP Post JSON

Jared Sherman picture Jared Sherman · Jun 3, 2014 · Viewed 55.8k times · Source

I am sure I'm doing something wrong here. I've followed every example I can find on stackoverflow and still haven't gotten this to work in my environment. I'd love to update my controls and environment, but I'm currently locked in with what I have.

I am using:

  • Delphi 7
  • Indy 10.0.52
  • ulkJSON.pas v1.07

I need to send this JSON to a URL:

"auth": {
    "applicationId": "appID",
    "applicationPassword": "pwd",
    "accountId": "acct",
    "userId": "dev"
}

There isn't anything terribly crazy about this, but when I try to post my request I tend to get a message that the request was Closed Gracefully. CheckIsReadable in IDSocketHandle.pas has Handleallocated = false. I'm not sure what I've done wrong in configuring my IdHTTP, but it just won't work.

I have tried examples from all these questions and several more, but none of these approaches seem to work for me:

Any tips would be greatly appreciated.

The current variant looks like this:

procedure Tformmaintestbed.btnJSONSendClick(Sender: TObject);
var
  code: Integer;
  sResponse: string;
  JsonToSend: TStringStream;
begin
  JsonToSend := TStringStream.Create(
    '{"auth": {"applicationId": "' + edApplication.text +
    '","applicationPassword": "' + edpassword.text +
    '","accountId": "' + edaccount.text +
    '","userId": "' + edUser.text +
    '"}}');
  try
    HTTP1.Request.ContentType := 'application/json';
    HTTP1.Request.ContentEncoding := 'utf-8';

    memoRequest.lines.clear;
    memoRequest.lines.add(JsonToSend);

    try
      sResponse := HTTP1.Post(cbAddress.text, JsonToSend);
    except
      on E: Exception do
        ShowMessage('Error on request: '#13#10 + e.Message);
    end;

    memoResponse.lines.clear;
    memoresponse.lines.add(sResponse);
  finally
    JsonToSend.Free();
  end;
end;

The idHTTP component is current set like this:

object HTTP1: TIdHTTP
  IOHandler = IdSSLIOHandlerSocketOpenSSL1
  AuthRetries = 0
  AuthProxyRetries = 0
  AllowCookies = True
  HandleRedirects = True
  ProxyParams.BasicAuthentication = False
  ProxyParams.ProxyPort = 0
  Request.ContentEncoding = 'utf-8'
  Request.ContentLength = -1
  Request.ContentRangeEnd = 0
  Request.ContentRangeStart = 0
  Request.ContentRangeInstanceLength = 0
  Request.ContentType = 'application/json'
  Request.Accept = 'application/json'
  Request.BasicAuthentication = False
  Request.UserAgent = 'Mozilla/3.0 (compatible; Indy Library)'
  HTTPOptions = [hoForceEncodeParams]
  Left = 564
  Top = 120
end

Answer

Remy Lebeau picture Remy Lebeau · Jun 4, 2014

HTTP1.Request.ContentEncoding should be HTTP1.Request.CharSet instead. UTF-8 is a charset encoding, not a content encoding. And then make sure your JSON data is actually encoded to UTF-8 before posting it. If you are using ASCII characters, the TStringStream code you showed is fine. But if you are using non-ASCII Characters, you need to encode them, such as with Utf8Encode(). TIdHTTP does not encode TStream data, it is sent as-is.

Procedure Tformmaintestbed.btnJSONSendClick(Sender: TObject);
var
  Json: string;
  sResponse: string;
  JsonToSend: TStringStream;
begin
  Json := '{"auth": {"applicationId": "' + edApplication.text +
    '","applicationPassword": "' + edpassword.text +
    '","accountId": "' + edaccount.text +
    '","userId": "' + edUser.text +
    '"}}';

  memoRequest.Text := Json;

  JsonToSend := TStringStream.Create(Utf8Encode(Json)); // D2007 and earlier only
  //in D2009 and later, use this instead:
  //JsonToSend := TStringStream.Create(Json, TEncoding.UTF8);
  try
    HTTP1.Request.ContentType := 'application/json';
    HTTP1.Request.CharSet := 'utf-8';

    try
      sResponse := HTTP1.Post(cbAddress.Text, JsonToSend);
    except
      on E: Exception do
        ShowMessage('Error on request: '#13#10 + e.Message);
    end;
  finally
    JsonToSend.Free;
  end;

  memoResponse.Text := sResponse;
end;

Alternatively:

Procedure Tformmaintestbed.btnJSONSendClick(Sender: TObject);
var
  Json: string;
  sResponse: string;
  JsonToSend: TMemoryStream;
begin
  Json := '{"auth": {"applicationId": "' + edApplication.text +
    '","applicationPassword": "' + edpassword.text +
    '","accountId": "' + edaccount.text +
    '","userId": "' + edUser.text +
    '"}}';

  memoRequest.Text := Json;

  JsonToSend := TMemoryStream.Create;
  try
    WriteStringToStream(JsonToSend, Json, enUTF8);
    JsonToSend.Position := 0;

    HTTP1.Request.ContentType := 'application/json';
    HTTP1.Request.CharSet := 'utf-8';

    try
      sResponse := HTTP1.Post(cbAddress.Text, JsonToSend);
    except
      on E: Exception do
        ShowMessage('Error on request: '#13#10 + e.Message);
    end;
  finally
    JsonToSend.Free;
  end;

  memoResponse.Text := sResponse;
end;