332

この質問は以前に尋ねられた可能性がありますが、決定的な回答はありませんでした。Retrofit リクエストの本文内に生の JSON 全体をどのように正確に投稿しますか?

ここで同様の質問を参照してください。または、フォーム URL をエンコードしてフィールドとして渡す必要があるというこの回答は正しいですか? 私が接続しているサービスは、投稿の本文で生の JSON を期待しているだけなので、そうしないことを本当に願っています。JSON データの特定のフィールドを探すようには設定されていません。

これを残りの部分で明確にしたいだけです。1 名がレトロフィットを使用しないと回答した。もう 1 つは、構文について確信が持てませんでした。別の人は、それは可能だと考えていますが、フォームが URL エンコードされてフィールドに配置されている場合に限ります (私の場合は受け入れられません)。いいえ、Android クライアント用にすべてのサービスを再コーディングすることはできません。はい、主要なプロジェクトでは、JSON コンテンツをフィールド プロパティ値として渡す代わりに、未加工の JSON を投稿するのが非常に一般的です。それを正しく理解して先に進みましょう。これがどのように行われるかを示すドキュメントまたは例を誰かが指摘できますか? または、それを行うことができる/行うべきではない正当な理由を提供してください。

更新: 100% 確実に言えることが 1 つあります。Google の Volley でこれを行うことができます。内蔵されています。Retrofit でこれを行うことはできますか?

4

25 に答える 25

496

@Body注釈は、単一の要求本文を定義します。

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body FooRequest body);
}

Retrofit はデフォルトで Gson を使用するため、FooRequestインスタンスはリクエストの唯一のボディとして JSON としてシリアル化されます。

public class FooRequest {
  final String foo;
  final String bar;

  FooRequest(String foo, String bar) {
    this.foo = foo;
    this.bar = bar;
  }
}

呼び出し:

FooResponse = foo.postJson(new FooRequest("kit", "kat"));

次の本体が生成されます。

{"foo":"kit","bar":"kat"}

Gsonのドキュメントには、オブジェクトのシリアライゼーションのしくみに関する詳細が記載されています。

ここで、本当に「生の」JSON を本文として送信したい場合 (ただし、これには Gson を使用してください!)、次のように使用できますTypedInput

interface Foo {
  @POST("/jayson")
  FooResponse postRawJson(@Body TypedInput body);
}

TypedInputは、「MIME タイプが関連付けられたバイナリ データ」として定義されます。上記の宣言で生データを簡単に送信するには、次の 2 つの方法があります。

  1. TypedByteArrayを使用して raw バイトと JSON MIME タイプを送信します。

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
    
  2. TypedStringをサブクラス化してTypedJsonStringクラスを作成します。

    public class TypedJsonString extends TypedString {
      public TypedJsonString(String body) {
        super(body);
      }
    
      @Override public String mimeType() {
        return "application/json";
      }
    }
    

    そして、#1 と同様のクラスのインスタンスを使用します。

于 2014-01-29T05:47:36.873 に答える
49

使用JsonObject方法は次のとおりです。

  1. 次のようにインターフェイスを作成します。

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
    
  2. jsons 構造に従って JsonObject を作成します。

    JsonObject obj = new JsonObject();
    JsonObject payerReg = new JsonObject();
    payerReg.addProperty("crc","aas22");
    payerReg.addProperty("payerDevManufacturer","Samsung");
    obj.add("payerReg",payerReg);
    /*json/*
        {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}}
    /*json*/
    
  3. サービスを呼び出します。

    service.registerPayer(obj, callBackRegistraPagador);
    
    Callback<JsonObject> callBackRegistraPagador = new Callback<JsonObject>(){
        public void success(JsonObject object, Response response){
            System.out.println(object.toString());
        }
    
        public void failure(RetrofitError retrofitError){
            System.out.println(retrofitError.toString());
        }
    };
    

そしてそれは!私の個人的な意見では、pojo を作成してクラスの混乱を処理するよりもはるかに優れています。これははるかにきれいです。

于 2015-07-27T16:08:41.010 に答える
12

上記TypedStringのサブクラスに関する Jake の提案が特に気に入っています。プッシュアップする予定の POST データの種類に基づいて、さまざまなサブクラスを作成し、それぞれに独自のカスタム セットの一貫した調整を加えることができます。

Retrofit API の JSON POST メソッドにヘッダー アノテーションを追加するオプションもあります…</p>

@Headers( "Content-Type: application/json" )
@POST("/json/foo/bar/")
Response fubar( @Body TypedString sJsonBody ) ;

…しかし、サブクラスを使用すると、より明らかに自己文書化されます。

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
于 2015-03-11T13:48:14.917 に答える
5

Retrofit で raw json を送信するために必要なもの。

1)必ず次のヘッダーを追加し、他の重複ヘッダーを削除してください。以来、 Retrofitの公式ドキュメントで、彼らは具体的に言及しています-

ヘッダーは互いに上書きしないことに注意してください。同じ名前のすべてのヘッダーがリクエストに含まれます。

@Headers({"Content-Type: application/json"})

2 ) コンバータ ファクトリを使用している場合は、json を String、JSONObject、JsonObject、さらには POJO として渡すことができます。また、仕事をScalarConverterFactoryするだけである必要はありません。GsonConverterFactory

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                     @Body JsonObject/POJO/String requestBody);

2) b. コンバータ ファクトリを使用していない場合は、Retrofit のドキュメントにあるように、okhttp3 の RequestBody を使用する必要があります。

オブジェクトは、Retrofit インスタンスで指定されたコンバーターを使用して変換されます。コンバーターが追加されていない場合は、RequestBody のみを使用できます。

RequestBody requestBody=RequestBody.create(MediaType.parse("application/json; charset=utf-8"),jsonString);

@POST("/urlPath")
@FormUrlEncoded
Call<Response> myApi(@Header("Authorization") String auth, @Header("KEY") String key, 
                 @Body RequestBody requestBody);

3)成功!!

于 2020-02-06T12:58:55.317 に答える
2

TommySM の回答に基づいて問題を解決しました (前を参照)。しかし、ログインする必要はありませんでした。次のように https GraphQL API をテストするために Retrofit2 を使用しました。

  1. json アノテーションを使用して BaseResponse クラスを定義しました (jackson.annotation.JsonProperty をインポート)。

    public class MyRequest {
        @JsonProperty("query")
        private String query;
    
        @JsonProperty("operationName")
        private String operationName;
    
        @JsonProperty("variables")
        private String variables;
    
        public void setQuery(String query) {
            this.query = query;
        }
    
        public void setOperationName(String operationName) {
            this.operationName = operationName;
        }
    
        public void setVariables(String variables) {
            this.variables = variables;
        }
    }
    
  2. インターフェイスで呼び出し手順を定義しました。

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
    
  3. テストの本体で apicall を呼び出します: MyRequest タイプの変数を作成します (たとえば、「myLittleRequest」)。

    Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest);
    RequestBody body = 
         RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
                        (new JSONObject(jsonParams)).toString());
    response = hereIsYourInterfaceName().apicall(body).execute();
    
于 2019-10-09T12:39:54.253 に答える
2

ここでの回答をより明確にするために、これが拡張機能の使用方法です。これは、Kotlin を使用している場合のみです。

MediaTypeおよびRequestBodycom.squareup.okhttp3:okhttp:4.0.1のオブジェクトを作成する古いメソッドを使用している場合、廃止されており、 Kotlin では使用できません。

拡張関数を使用して、文字列からMediaTypeオブジェクトとResponseBodyオブジェクトを取得する場合は、まず、それらを使用する予定のクラスに次の行を追加します。

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

この方法でMediaTypeのオブジェクトを直接取得できるようになりました

val mediaType = "application/json; charset=utf-8".toMediaType()

RequestBodyのオブジェクトを取得するには、まず送信する JSONObject をこの方法で文字列に変換します。mediaType オブジェクトを渡す必要があります。

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
于 2019-08-08T12:41:34.603 に答える
1

私はこれを試しました: レトロフィット インスタンスを作成するとき、このコンバーター ファクトリをレトロフィット ビルダーに追加します。

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
于 2018-10-18T13:32:25.490 に答える