Come POST JSON intero crudo nel corpo di una richiesta di retrofit?


285

Questa domanda potrebbe essere stata posta prima, ma no, non è stata data una risposta definitiva. In che modo esattamente un post JSON intero non elaborato all'interno del corpo di una richiesta di retrofit?

Vedi domanda simile qui . O questa risposta è corretta e deve essere codificata come URL e passata come campo ? Spero davvero di no, dato che i servizi a cui mi sto collegando si aspettano solo JSON crudo nel corpo del post. Non sono impostati per cercare un campo particolare per i dati JSON.

Voglio solo chiarire questo con i restanti una volta per tutte. Una persona ha risposto di non usare Retrofit. L'altro non era certo della sintassi. Un altro pensa di sì che può essere fatto, ma solo se la sua forma è codificata in URL e posizionata in un campo (questo non è accettabile nel mio caso). No, non posso ricodificare tutti i servizi per il mio client Android. E sì, è molto comune nei grandi progetti pubblicare JSON non elaborati anziché passare il contenuto JSON come valori delle proprietà dei campi. Facciamo la cosa giusta e andiamo avanti. Qualcuno può indicare la documentazione o l'esempio che mostra come viene fatto? O fornire un motivo valido per cui non può / non si deve fare.

AGGIORNAMENTO: Una cosa che posso dire con certezza al 100%. PUOI farlo in Volley di Google. È integrato. Possiamo farlo in Retrofit?


7
Il post di Jake Wharton è corretto! Segna come risposta!
edotassi,

1
Potresti usare jsonObject meglio.
superutente

funziona perfettamente con RequestBodyquesto -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);per una risposta dettagliata futurestud.io/tutorials/…
Kidus Tekeste

Risposte:


461

L' @Bodyannotazione definisce un singolo corpo di richiesta.

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

Poiché Retrofit utilizza Gson per impostazione predefinita, le FooRequestistanze verranno serializzate come JSON come unico corpo della richiesta.

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

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

Chiamando con:

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

Produrrà il seguente corpo:

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

I documenti Gson hanno molto di più su come funziona la serializzazione degli oggetti.

Ora, se vuoi davvero inviare JSON "grezzo" come corpo (ma per favore usa Gson per questo!) Puoi ancora usare TypedInput:

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

TypedInput è definito come "Dati binari con un tipo MIME associato". Esistono due modi per inviare facilmente dati non elaborati con la dichiarazione sopra:

  1. Utilizzare TypedByteArray per inviare byte non elaborati e il tipo mime JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Sottoclasse TypedString per creare una TypedJsonStringclasse:

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

    E quindi usa un'istanza di quella classe simile al n. 1.


5
Molto bene, comunque, c'è qualcosa da fare senza fare i pojos?
superUser

28
Questo non funziona su retrofit 2. Le classi TypedInput e TypedString sono state rimosse.
Ahmed Hegazy,

2
@jakewharton Cosa possiamo fare da TypedStringquando è stato rimosso?
Jared Burrows,

12
Per Retrofit2, è possibile utilizzare RequestBodyper creare un corpo grezzo.
bnorm,

4
Ricevo questa eccezionejava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal,

156

Invece delle classi possiamo anche usare direttamente il HashMap<String, Object>per inviare i parametri del corpo, ad esempio

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}

2
In quel momento è possibile creare una mappa hash come HashMap <String, Object>, può essere possibile per la creazione di matrici e oggetti complessi JSON.
discente

2
Questo è eccellente se non vuoi essere legato a un POJO di qualche tipo.
Tim

2
@Nil non puoi inviare oggetti json usando retrofit ... aderisci con pojo o la mia risposta ... questa è la natura del retrofit.se vuoi di più su questo chiedi a Jake Wharton che è un ragazzo sviluppatore di retrofit, la sua risposta è disponibile anche con pojo .
studente

5
Vado IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>con Moshi. Penso che Gson sia necessario per far funzionare tutto questo
osrl

2
Se usi Kotlin usa una hashmap di <String, Any>
peresisUser

148

Sì, lo so che è tardi, ma probabilmente qualcuno ne trarrebbe beneficio.

Utilizzando Retrofit2:

Mi sono imbattuto in questo problema la scorsa notte migrando da Volley a Retrofit2 (e come afferma OP, questo è stato integrato in Volley con JsonObjectRequest), e sebbene la risposta di Jake sia quella corretta per Retrofit1.9 , Retrofit2 non ha TypedString.

Il mio caso richiedeva l'invio di un Map<String,Object>che potesse contenere alcuni valori null, convertito in un oggetto JSONObject (che non volerà con @FieldMap, né caratteri speciali, alcuni vengono convertiti), quindi seguendo il suggerimento di @bnorms, e come affermato da Square :

È possibile specificare un oggetto da utilizzare come corpo di richiesta HTTP con l'annotazione @Body.

L'oggetto verrà inoltre convertito utilizzando un convertitore specificato nell'istanza di Retrofit. Se non viene aggiunto alcun convertitore, è possibile utilizzare solo RequestBody.

Quindi questa è un'opzione usando RequestBodye ResponseBody:

Nella tua interfaccia utilizzare @BodyconRequestBody

public interface ServiceApi
{
    @POST("prefix/user/{login}")
    Call<ResponseBody> login(@Path("login") String postfix, @Body RequestBody params);  
}

Nel punto di chiamata crea un RequestBody, dichiarando che è MediaType e usa JSONObject per convertire la tua mappa nel formato corretto:

Map<String, Object> jsonParams = new ArrayMap<>();
//put something inside the map, could be null
jsonParams.put("code", some_code);

RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(new JSONObject(jsonParams)).toString());
//serviceCaller is the interface initialized with retrofit.create...
Call<ResponseBody> response = serviceCaller.login("loginpostfix", body);
      
response.enqueue(new Callback<ResponseBody>()
    {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> rawResponse)
        {
            try
            {
             //get your response....
              Log.d(TAG, "RetroFit2.0 :RetroGetLogin: " + rawResponse.body().string());
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable throwable)
        {
        // other stuff...
        }
    });

Spero che questo aiuti chiunque!


Un'elegante versione Kotlin di cui sopra, per consentire di astrarre i parametri dalla conversione JSON nel resto del codice dell'applicazione:

interface ServiceApi {

    fun login(username: String, password: String) =
            jsonLogin(createJsonRequestBody(
                "username" to username, "password" to password))

    @POST("/api/login")
    fun jsonLogin(@Body params: RequestBody): Deferred<LoginResult>

    private fun createJsonRequestBody(vararg params: Pair<String, String>) =
            RequestBody.create(
                okhttp3.MediaType.parse("application/json; charset=utf-8"), 
                JSONObject(mapOf(*params)).toString())

}

2
Sì, sto vedendo molte risposte complicate dappertutto per questo. Se stai usando Retrofit2 e vuoi fare il tiro al volo JsonObjectRequest, tutto ciò che devi fare è questo. Buona risposta.
VicVu,

2
Retrofit aggiunge una chiave denominata "nameValuePairs" all'inizio di tutti gli oggetti json. Come posso rimuovere questo @TommySM
nr5

1
Grazie! Questo ha risolto il mio problema. Ora posso inviare direttamente JSONObject senza creare POJO.
Erfan GLMPR,

1
Questa è l'unica soluzione che mi ha aiutato a post a null valueraggiungere una proprietà in requestBody che altrimenti veniva ignorata.
Shubhral,

So di essere in ritardo, ma cosa c'è jsonParams.put("code", some_code);nella terza riga?
Naveen Niraula,

81

In Retrofit2 , quando si desidera inviare i parametri in raw è necessario utilizzare gli scalari .

prima aggiungi questo nel tuo voto:

compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:converter-scalars:2.3.0'

La tua interfaccia

public interface ApiInterface {

    String URL_BASE = "http://10.157.102.22/rest/";

    @Headers("Content-Type: application/json")
    @POST("login")
    Call<User> getUser(@Body String body);

}

Attività

   public class SampleActivity extends AppCompatActivity implements Callback<User> {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ApiInterface.URL_BASE)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        ApiInterface apiInterface = retrofit.create(ApiInterface.class);


        // prepare call in Retrofit 2.0
        try {
            JSONObject paramObject = new JSONObject();
            paramObject.put("email", "sample@gmail.com");
            paramObject.put("pass", "4384984938943");

            Call<User> userCall = apiInterface.getUser(paramObject.toString());
            userCall.enqueue(this);
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void onResponse(Call<User> call, Response<User> response) {
    }

    @Override
    public void onFailure(Call<User> call, Throwable t) {
    }
}

10
Il trucco qui è l'adattatore scalare prima di Gson, altrimenti Gson avvolgerà il tuo JSON serializzato manualmente in una stringa.
TWiStErRob,

2
jonathan-nolasco-barrientos devi cambiare .baseUrl (ApiInterface.ENDPOINT) in .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi,

2
Quando si utilizza GsonConverterFactory, .toString()non è necessario. Puoi dichiarare Call<User> getUser(@Body JsonObject body);usando JsonObjectinvece di JSONObjecte passare paramObjectdirettamente. Funzionerà bene.
Igor de Lorenzi,

1
@IgordeLorenzi risolve il mio problema, poiché sto usando lo stivale a molla per recuperare il json solo JsonObject da gson funziona bene
haidarvm,

1
@IgordeLorenzi C'è una differenza quale è meglio usare JSONObject o JsonObject con gli scalari.
Sumit Shukla,

44

L'utilizzo JsonObjectè così:

  1. Crea la tua interfaccia in questo modo:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Rendi JsonObject secondo la struttura jsons.

    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. Chiama il servizio:

    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());
        }
    };

E quello è suo! Secondo la mia opinione personale, è molto meglio che fare pojos e lavorare con il pasticcio di classe. Questo è molto più pulito.


1
Cosa succede se non desidero inviare un valore specifico nella classe jsonobject. quale annotaion posso usare sopra verificabile per quello?
Ali Gürelli,

1
Come puoi vedere nell'esempio sopra ... JsonObject in quanto è un oggetto, non usa alcuna annotazione. Nel tuo caso, se non desideri inviare un valore specifico, potresti non aggiungerlo come proprietà ...
superUser

1
Voglio dire, non voglio inviare un valore dichiarato nella classe. A proposito ho risolto il problema. C'era un'annotazione per ciò che il nome è esposto.
Ali Gürelli,

2
Questo è il modo più flessibile. Puoi costruire il tuo oggetto json anche se non sai quanti campi avrai o anche se non conosci i loro nomi +1 da me
Stoycho Andreev,

1
sto ottenendo un errore I metodi di servizio non possono restituire nulla. per il metodo APIServices.signUpUser
Erum

11

Mi piace in particolare il suggerimento di Jake sulla TypedStringsottoclasse sopra . Potresti davvero creare una varietà di sottoclassi in base al tipo di dati POST che prevedi di eseguire il push up, ognuno con il proprio set personalizzato di modifiche coerenti.

Hai anche la possibilità di aggiungere un'annotazione di intestazione ai tuoi metodi POST JSON nell'API di retrofit ...

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

... ma l'uso di una sottoclasse è ovviamente più autocontrollo.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;

1
Ho salvato la giornata con un chiaro esempio usando TypedJsonString dal suggerimento JW
miroslavign

10

1) Aggiungi dipendenze-

 compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

2) crea la classe Api Handler

    public class ApiHandler {


  public static final String BASE_URL = "URL";  

    private static Webservices apiService;

    public static Webservices getApiService() {

        if (apiService == null) {

           Gson gson = new GsonBuilder()
                    .setLenient()
                    .create();
            Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).baseUrl(BASE_URL).build();

            apiService = retrofit.create(Webservices.class);
            return apiService;
        } else {
            return apiService;
        }
    }


}

3) crea classi bean da Json schema 2 pojo

Ricorda
-Target language: Java -Source tipo: JSON -Stile di annotazione: Gson -seleziona Includi getter e setter -anche puoi selezionare Consenti proprietà aggiuntive

http://www.jsonschema2pojo.org/

4) interfaccia per la chiamata API

    public interface Webservices {

@POST("ApiUrlpath")
    Call<ResponseBean> ApiName(@Body JsonObject jsonBody);

}

se si dispone di parametri di un modulo-dati, aggiungere sotto la riga

@Headers("Content-Type: application/x-www-form-urlencoded")

Un altro modo per il parametro form-data controlla questo link

5) crea JsonObject per passare al corpo come parametro

 private JsonObject ApiJsonMap() {

    JsonObject gsonObject = new JsonObject();
    try {
        JSONObject jsonObj_ = new JSONObject();
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");
        jsonObj_.put("key", "value");


        JsonParser jsonParser = new JsonParser();
        gsonObject = (JsonObject) jsonParser.parse(jsonObj_.toString());

        //print parameter
        Log.e("MY gson.JSON:  ", "AS PARAMETER  " + gsonObject);

    } catch (JSONException e) {
        e.printStackTrace();
    }

    return gsonObject;
}

6) Chiama Api in questo modo

private void ApiCallMethod() {
    try {
        if (CommonUtils.isConnectingToInternet(MyActivity.this)) {
            final ProgressDialog dialog;
            dialog = new ProgressDialog(MyActivity.this);
            dialog.setMessage("Loading...");
            dialog.setCanceledOnTouchOutside(false);
            dialog.show();

            Call<ResponseBean> registerCall = ApiHandler.getApiService().ApiName(ApiJsonMap());
            registerCall.enqueue(new retrofit2.Callback<ResponseBean>() {
                @Override
                public void onResponse(Call<ResponseBean> registerCall, retrofit2.Response<ResponseBean> response) {

                    try {
                        //print respone
                        Log.e(" Full json gson => ", new Gson().toJson(response));
                        JSONObject jsonObj = new JSONObject(new Gson().toJson(response).toString());
                        Log.e(" responce => ", jsonObj.getJSONObject("body").toString());

                        if (response.isSuccessful()) {

                            dialog.dismiss();
                            int success = response.body().getSuccess();
                            if (success == 1) {



                            } else if (success == 0) {



                            }  
                        } else {
                            dialog.dismiss();


                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                        try {
                            Log.e("Tag", "error=" + e.toString());

                            dialog.dismiss();
                        } catch (Resources.NotFoundException e1) {
                            e1.printStackTrace();
                        }

                    }
                }

                @Override
                public void onFailure(Call<ResponseBean> call, Throwable t) {
                    try {
                        Log.e("Tag", "error" + t.toString());

                        dialog.dismiss();
                    } catch (Resources.NotFoundException e) {
                        e.printStackTrace();
                    }
                }

            });

        } else {
            Log.e("Tag", "error= Alert no internet");


        }
    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
}

9

Ho scoperto che quando usi un oggetto composto come @Bodyparametro, non potrebbe funzionare bene con il Retrofit GSONConverter(supponendo che lo stai usando). Devi usarlo JsonObjecte non JSONObjectquando lavori con quello, si aggiunge NameValueParamssenza essere prolisso - puoi vedere solo se aggiungi un'altra dipendenza dell'intercettore di registrazione e di altri shenanigani.

Quindi quello che ho trovato l'approccio migliore per affrontare questo sta usando RequestBody. Trasforma il tuo oggetto in RequestBodyuna semplice chiamata api e lo avvii. Nel mio caso sto convertendo una mappa:

   val map = HashMap<String, Any>()
        map["orderType"] = orderType
        map["optionType"] = optionType
        map["baseAmount"] = baseAmount.toString()
        map["openSpotRate"] = openSpotRate.toString()
        map["premiumAmount"] = premiumAmount.toString()
        map["premiumAmountAbc"] = premiumAmountAbc.toString()
        map["conversionSpotRate"] = (premiumAmountAbc / premiumAmount).toString()
        return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), JSONObject(map).toString())

e questa è la chiamata:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>

2
Bene, questo mi ha aiutato dopo aver cercato su Google durante la notte.
W4R10CK,

8

Aggiungi ScalarsConverterFactory per il retrofit:

in pendenza:

implementation'com.squareup.retrofit2:converter-scalars:2.5.0'

il tuo retrofit:

retrofit = new Retrofit.Builder()
            .baseUrl(WEB_DOMAIN_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

cambia il parametro @Body dell'interfaccia di chiamata in String, non dimenticare di aggiungere @Headers("Content-Type: application/json"):

@Headers("Content-Type: application/json")
@POST("/api/getUsers")
Call<List<Users>> getUsers(@Body String rawJsonString);

ora puoi pubblicare raw json.


6

È possibile utilizzare hashmap se non si desidera creare una classe pojo per ogni chiamata API.

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","this@gmail.com");
        hashMap.put("password","1234");

E poi invia così

Call<JsonElement> register(@Body HashMap registerApiPayload);

5

usa il seguente per inviare json

final JSONObject jsonBody = new JSONObject();
    try {

        jsonBody.put("key", "value");

    } catch (JSONException e){
        e.printStackTrace();
    }
    RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),(jsonBody).toString());

e passalo a url

@Body RequestBody key

4

Dopo così tanti sforzi, abbiamo scoperto che la differenza di base è che devi inviare il parametro JsonObjectinvece che JSONObjectcome.


Stavo anche facendo lo stesso errore: p
Mehtab Ahmed

4

Sulla base della risposta migliore, ho una soluzione per non dover fare POJO per ogni richiesta.

Esempio, voglio pubblicare questo JSON.

{
    "data" : {
        "mobile" : "qwer",
        "password" : "qwer"
    },
    "commom" : {}
}

quindi, creo una classe comune come questa:

import java.util.Map;
import java.util.HashMap;

public class WRequest {

    Map<String, Object> data;
    Map<String, Object> common;

    public WRequest() {
        data = new HashMap<>();
        common = new HashMap<>();
    }
}

Alla fine, quando ho bisogno di un json

WRequest request = new WRequest();
request.data.put("type", type);
request.data.put("page", page);

La richiesta contrassegnata come annotazione @Bodypuò quindi passare a Retrofit.


4

Se non vuoi creare lezioni extra o utilizzare JSONObjectpuoi usare a HashMap.

Interfaccia di retrofit:

@POST("/rest/registration/register")
fun signUp(@Body params: HashMap<String, String>): Call<ResponseBody>

Chiamata:

val map = hashMapOf(
    "username" to username,
    "password" to password,
    "firstName" to firstName,
    "surname" to lastName
)

retrofit.create(TheApi::class.java)
     .signUp(map)
     .enqueue(callback)

3

Cose necessarie per inviare json non elaborate in Retrofit.

1) Assicurati di aggiungere la seguente intestazione e rimuovere qualsiasi altra intestazione duplicata. Poiché, sulla documentazione ufficiale di Retrofit, menzionano in modo specifico-

Si noti che le intestazioni non si sovrascrivono a vicenda. Tutte le intestazioni con lo stesso nome verranno incluse nella richiesta.

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

2) a. Se stai usando una fabbrica di convertitori puoi passare il tuo json come String, JSONObject, JsonObject e persino un POJO. Inoltre ho controllato, avendo ScalarConverterFactorynon è necessario solo GsonConverterFactoryil lavoro.

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

2) b. Se NON si utilizza alcuna fabbrica di convertitori, è NECESSARIO utilizzare RequestBody di okhttp3 come dice la documentazione di Retrofit-

L'oggetto verrà inoltre convertito utilizzando un convertitore specificato nell'istanza di Retrofit. Se non viene aggiunto alcun convertitore, è possibile utilizzare solo 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) Successo !!


2

Questo è ciò che mi funziona per l'attuale versione di retrofit 2.6.2 ,

Prima di tutto, dobbiamo aggiungere un convertitore scalare all'elenco delle nostre dipendenze Gradle, che si occuperebbe di convertire gli oggetti java.lang.String in corpi di richiesta testo / semplici,

implementation'com.squareup.retrofit2:converter-scalars:2.6.2'

Quindi, dobbiamo passare una fabbrica di convertitori al nostro costruttore di Retrofit. In seguito dirà a Retrofit come convertire il parametro @Body passato al servizio.

private val retrofitBuilder: Retrofit.Builder by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
}

Nota: nel mio costruttore di retrofit ho due convertitori Gsone Scalarspuoi usarli entrambi ma per inviare il corpo di Json dobbiamo concentrarci, Scalarsquindi se non hai bisogno di Gsonrimuoverlo

Quindi servizio di retrofit con un parametro body String.

@Headers("Content-Type: application/json")
@POST("users")
fun saveUser(@Body   user: String): Response<MyResponse>

Quindi creare il corpo JSON

val user = JsonObject()
 user.addProperty("id", 001)
 user.addProperty("name", "Name")

Chiama il tuo servizio

RetrofitService.myApi.saveUser(user.toString())

2

✅✅✅✅✅✅✅✅✅✅✅✅ Soluzione di lavoro ✅✅✅✅✅✅✅✅✅✅✅✅

Durante la creazione OkHttpClient verrà utilizzato per il Retrofit.

aggiungi un intercettore come questo.

 private val httpClient = OkHttpClient.Builder()
        .addInterceptor (other interceptors)
        ........................................

        //This Interceptor is the main logging Interceptor
        .addInterceptor { chain ->
            val request = chain.request()
            val jsonObj = JSONObject(Gson().toJson(request))

            val requestBody = (jsonObj
            ?.getJSONObject("tags")
            ?.getJSONObject("class retrofit2.Invocation")
            ?.getJSONArray("arguments")?.get(0) ?: "").toString()
            val url = jsonObj?.getJSONObject("url")?.getString("url") ?: ""

            Timber.d("gsonrequest request url: $url")
            Timber.d("gsonrequest body :$requestBody")

            chain.proceed(request)
        }

        ..............
        // Add other configurations
        .build()

Ora il corpo URL e la richiesta di ogni vostro retrofit di chiamata sarà registrata in Logcat. Filtra per"gsonrequest"


1

Ho provato questo: quando crei l'istanza di Retrofit, aggiungi questa fabbrica di convertitori al costruttore di retrofit:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )

1

Risolto il mio problema in base alla risposta TommySM (vedi precedente). Ma non avevo bisogno di effettuare il login, ho usato Retrofit2 per testare l'API GraphQL https in questo modo:

  1. Definita la mia classe BaseResponse con l'aiuto delle annotazioni json (import 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. Definita la procedura di chiamata nell'interfaccia:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Chiamato apicall nel corpo del test: crea una variabile di tipo MyRequest (ad esempio "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();

0

Per maggiore chiarezza sulle risposte fornite qui, ecco come è possibile utilizzare le funzioni di estensione. Questo è solo se stai usando Kotlin

Se stai utilizzando com.squareup.okhttp3:okhttp:4.0.1i metodi precedenti di creazione di oggetti di MediaType e RequestBody sono stati deprecati e non possono essere utilizzati in Kotlin .

Se si desidera utilizzare le funzioni di estensione per ottenere un oggetto MediaType e un oggetto ResponseBody dalle stringhe, aggiungere innanzitutto le seguenti righe alla classe in cui si prevede di utilizzarle.

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

Ora puoi ottenere direttamente un oggetto di MediaType in questo modo

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

Per ottenere un oggetto di RequestBody, converti prima l'oggetto JSONObject che desideri inviare a una stringa in questo modo. Devi passare l'oggetto mediaType ad esso.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)

0

Volevo confrontare la velocità di volley e retrofit per l'invio e la ricezione dei dati che ho scritto sotto il codice (per la parte retrofit)

prima dipendenza:

dependencies {
     implementation 'com.squareup.retrofit2:retrofit:2.4.0'
     implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}

Quindi interfaccia:

 public interface IHttpRequest {

    String BaseUrl="https://example.com/api/";

    @POST("NewContract")
    Call<JsonElement> register(@Body HashMap registerApiPayload);
}

e una funzione per impostare i parametri per pubblicare i dati sul server (in MainActivity):

private void Retrofit(){

    Retrofit retrofitRequest = new Retrofit.Builder()
            .baseUrl(IHttpRequest.BaseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    // set data to send
    HashMap<String,String> SendData =new HashMap<>();
    SendData.put("token","XYXIUNJHJHJHGJHGJHGRTYTRY");
    SendData.put("contract_type","0");
    SendData.put("StopLess","37000");
    SendData.put("StopProfit","48000");

    final IHttpRequest request=retrofitRequest.create(IHttpRequest.class);

    request.register(SendData).enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {
            if (response.isSuccessful()){
                Toast.makeText(getApplicationContext(),response.body().toString(),Toast.LENGTH_LONG).show();
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable t) {

        }
    });

}

E ho trovato Retrofit più veloce del volley nel mio caso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.