3

私はこの問題に何時間も取り組んできましたが、実際には何の前進もありませんでした。動作する古いソリューションがありますが、それを Indy に移植して、コードの信頼性を高め、保守を容易にしようとしています。

HTTP POST メッセージを使用して送信されたリクエストを処理するサーブレットがあります。メッセージには「コマンド」という 1 つのパラメータがあり、その値によってサーブレットの動作が決まります。

現在、私はこれを持っています:

procedure TIndyLoginServer.SendRequest(Command, Json: string; Request: TRequest);
var
  Params: TIdStrings;
  ServerResponse: string;
begin
  // Build parameters
  Params := TStringList.Create();
  Params.Add('command=' + Command);

  try
    // Content type should really be 'application/json' but then the parameters stop working
    FIndyHttp.Request.ContentType := 'application/x-www-form-urlencoded'; 
    ServerResponse := FIndyHttp.Post(FUrl, Params);
    Request.OnRequestFinished(ServerResponse, '', '');
  except
    on E: EIdHTTPProtocolException do
    begin
      Request.OnRequestFinished('', E.Message, '');
    end;
    on E: EIdSocketError do
    begin
      if E.LastError = Id_WSAETIMEDOUT then      
        Request.OnRequestTimedOut();
    end;
    on E: EIdException do
    begin
      Request.OnRequestFinished('', E.Message, '');
    end;
  end;
end;

この種の作業は、コマンドがサーブレットに到達し、期待どおりに機能し始めます。問題は、パラメーターに加えて、JSON エンコードされたオブジェクトを POST 要求と共に送信できるようにする必要があることです。Java サーブレットは、次のコード行を使用して、JSON でエンコードされたオブジェクトを受け取ります。

final BufferedReader r = req.getReader();

「req」は明らかに着信 POST 要求であり、バッファリングされたリーダーは後でオブジェクトをデコードするために使用されます。ただし、サーブレットがデータを読み取れるように、JSON 文字列を TidHTTP インスタンスにアタッチする方法は、一生わかりません。

私が見ることができる提案や例はありますか? 私が見つけたのは、ファイルを送信する方法だけです。多分それは私が探しているものですか?

また、パラメーター リストを壊さずに、リクエストのコンテンツ タイプを「application/json」に設定するにはどうすればよいですか? 変更すると、POST リクエストは引き続きサーバーに到達しますが、「コマンド」パラメーターは見つかりません。

4

2 に答える 2

3

ほとんどのヒント: "application/x-www-form-urlencoded" を使用すると、サーバー側は次のようなキーと値のペアを期待します。

key1=value1&key2=value2 etc.

この場合、JSON テキストをキーの値として送信できます。次に例を示します。

{...}
Params.Add('command=' + Command);
Params.Add('jsonText=' + json);
FIndyHttp.Request.ContentType := 'application/x-www-form-urlencoded'; 
ServerResponse := FIndyHttp.Post(FUrl, Params);
{...}

"application/json" を使用して HTTP サーバーに伝えます。リクエストの本文全体 (ヘッダーの後の部分) に JSON テキストが含まれます。

PHP では、「入力ストリーム」を使用してリクエストの「本文」にアクセスできます。

$jsonText = file_get_contents("php://input")
$jsonObject = json_decode($jsonText )

JAVAで似たようなものを見つけてみてください。

アップデート:

TIdStrings は、リクエストが「application/x-www-form-urlencoded」になるように準備しているようです。Remy Lebeau がここで提案しているように、JSON 文字列を TStream の子孫 (tMemoryStream など) に保存し、そのまま (つまり RAW) 転送します。tIdHttp.POST には、TStream を受け入れるオーバーライドがあります。この場合、TIdHTTP.Request.ContentType = 'application/json' を試してください。それはそのように動作するはずですか?

于 2013-04-18T15:08:53.713 に答える
2

私はそれを解決したと思います。これがこれを行う最も美しい方法かどうかはわかりませんが、私が望むことはできるようです。

これがコードです!

procedure TIndyLoginServer.SendRequest(Command, Json: string;
  Request: TRequest);
var
  JsonToSend: TIdStringStream;
  ServerResponse: string;
  Url: string;
begin
  // Build parameters
  JsonToSend := TIdStringStream.Create(Json);

  try
    try
      FIndyHttp.Request.Accept := 'application/json';
      FIndyHttp.Request.ContentType := 'application/json';
      FIndyHttp.Request.ContentEncoding := 'utf-8';


      Url := FUrl +'?command=' + Command;
      ServerResponse := FIndyHttp.Post(Url, JsonToSend);

      Request.OnRequestFinished(ServerResponse, '', '');
    except
      on E: EIdHTTPProtocolException do
      begin
        Request.OnRequestFinished('', E.Message, '');
      end;
      on E: EIdSocketError do
      begin
        if E.LastError = Id_WSAETIMEDOUT then
          Request.OnRequestTimedOut();
      end;
      on E: EIdException do
      begin
        Request.OnRequestFinished('', E.Message, '');
      end;
    end;
  finally
    JsonToSend.Free();
  end;
end;
于 2013-04-18T15:54:27.557 に答える