Wie poste ich rohen gesamten JSON in den Text einer Nachrüstanforderung?


284

Diese Frage wurde vielleicht schon einmal gestellt, aber nein, sie wurde nicht endgültig beantwortet. Wie genau postet man rohen ganzen JSON im Hauptteil einer Retrofit-Anfrage?

Siehe ähnliche Frage hier . Oder ist diese Antwort richtig, dass sie formularcodiert und als Feld übergeben werden muss ? Ich hoffe wirklich nicht, da die Dienste, mit denen ich mich verbinde, nur rohen JSON im Hauptteil des Beitrags erwarten. Sie sind nicht so eingerichtet, dass sie nach einem bestimmten Feld für die JSON-Daten suchen.

Ich möchte dies nur ein für alle Mal mit den Restperts klären . Eine Person antwortete, Retrofit nicht zu verwenden. Der andere war sich der Syntax nicht sicher. Ein anderer meint, ja, es kann getan werden, aber nur, wenn seine Form url-codiert und in einem Feld platziert ist (das ist in meinem Fall nicht akzeptabel). Nein, ich kann nicht alle Dienste für meinen Android-Client neu codieren. Und ja, es ist in großen Projekten sehr üblich, unformatiertes JSON zu veröffentlichen, anstatt JSON-Inhalte als Feldeigenschaftswerte zu übergeben. Lassen Sie es uns richtig machen und weitermachen. Kann jemand auf die Dokumentation oder das Beispiel verweisen, das zeigt, wie dies gemacht wird? Oder geben Sie einen gültigen Grund an, warum dies nicht möglich ist / sein sollte.

UPDATE: Eines kann ich mit 100% iger Sicherheit sagen. Sie können dies in Googles Volley tun. Es ist direkt eingebaut. Können wir dies in Retrofit tun?


7
Der Beitrag von Jake Wharton ist korrekt! Als Antwort markieren!
Edotassi

1
Sie könnten jsonObject besser verwenden.
SuperUser

funktioniert perfekt mit RequestBodyso -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);für detaillierte Antwort futurestud.io/tutorials/…
Kidus Tekeste

Antworten:


461

Die @BodyAnmerkung definiert einen einzelnen Anforderungshauptteil.

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

Da Retrofit standardmäßig Gson verwendet, werden die FooRequestInstanzen als JSON als einziger Hauptteil der Anforderung serialisiert.

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

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

Anrufen mit:

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

Ergibt den folgenden Körper:

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

In den Gson-Dokumenten erfahren Sie viel mehr über die Funktionsweise der Objektserialisierung.

Wenn Sie wirklich "rohen" JSON als Körper selbst senden möchten (aber verwenden Sie dazu bitte Gson!), Können Sie trotzdem Folgendes verwenden TypedInput:

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

TypedInput ist definiert als "Binärdaten mit einem zugeordneten MIME-Typ". Es gibt zwei Möglichkeiten, Rohdaten mit der obigen Deklaration einfach zu senden:

  1. Verwenden Sie TypedByteArray , um Rohbytes und den JSON- MIME-Typ zu senden:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Unterklasse TypedString zum Erstellen einer TypedJsonStringKlasse:

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

    Verwenden Sie dann eine Instanz dieser Klasse ähnlich # 1.


5
Sehr gut, gibt es trotzdem etwas, um dies zu machen, ohne die Pojos zu machen?
SuperUser

28
Dies funktioniert bei Nachrüstung 2 nicht. Die Klassen TypedInput und TypedString wurden entfernt.
Ahmed Hegazy

2
@jakewharton Was können wir tun, TypedStringseit es entfernt wurde?
Jared Burrows

12
Für Retrofit2 können Sie RequestBodyeinen Rohkörper erstellen.
Bnorm

4
Ich java.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
bekomme

154

Anstelle von Klassen können wir beispielsweise auch direkt verwenden HashMap<String, Object>, um Körperparameter zu senden

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

2
Zu diesem Zeitpunkt können Sie eine Hash-Map wie HashMap <String, Object> erstellen. Es kann möglich sein, komplexe Arrays und Objekte JSON zu erstellen.
Lerner

2
Dies ist hervorragend, wenn Sie nicht an ein POJO gebunden sein möchten.
Tim

2
@Nein Sie können kein JSON-Objekt mit Nachrüstung senden ... Sie halten sich an Pojo oder meine Antwort ... dies ist die Art der Nachrüstung. Wenn Sie mehr darüber erfahren möchten, fragen Sie Jake Wharton, ob er ein Nachrüst-Entwickler ist. Seine Antwort ist auch mit Pojo verfügbar .
Lerner

5
Ich komme IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>mit Moshi. Ich denke, Gson wird benötigt, damit dies funktioniert
osrl

2
Wenn Sie Kotlin verwenden, verwenden Sie eine Hashmap von <String, Any>
peresisUser

148

Ja, ich weiß, dass es spät ist, aber wahrscheinlich würde jemand davon profitieren.

Verwenden von Retrofit2:

Ich bin gestern Abend auf dieses Problem bei der Migration von Volley zu Retrofit2 gestoßen (und wie OP feststellt, wurde dies direkt in Volley integriert JsonObjectRequest), und obwohl Jakes Antwort die richtige für Retrofit1.9 ist , hat Retrofit2 keine TypedString.

In meinem Fall musste Map<String,Object>ein gesendet werden, das einige Nullwerte enthalten konnte, die in ein JSONObject konvertiert wurden (das nicht mitfliegt @FieldMap, spezielle Zeichen auch nicht konvertiert werden, einige werden konvertiert). Befolgen Sie daher den @bnorms-Hinweis und wie von Square angegeben :

Ein Objekt kann zur Verwendung als HTTP-Anforderungshauptteil mit der Annotation @Body angegeben werden.

Das Objekt wird auch mit einem Konverter konvertiert, der in der Retrofit-Instanz angegeben ist. Wenn kein Konverter hinzugefügt wird, kann nur RequestBody verwendet werden.

Dies ist also eine Option mit RequestBodyund ResponseBody:

In Ihrer Schnittstelle verwenden @BodymitRequestBody

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

Erstellen RequestBodySie in Ihrem Aufrufpunkt ein , geben Sie an, dass es sich um MediaType handelt, und konvertieren Sie Ihre Karte mit JSONObject in das richtige Format:

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

Hoffe das hilft jemandem!


Eine elegante Kotlin-Version des oben genannten, mit der Sie die Parameter der JSON-Konvertierung im Rest Ihres Anwendungscodes abstrahieren können:

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
Ja, ich sehe überall eine Menge komplizierter Antworten. Wenn Sie Retrofit2 verwenden und Volleyball spielen möchten, müssen JsonObjectRequestSie dies nur tun. Gute Antwort.
VicVu

2
Durch Nachrüsten wird ein Schlüssel mit dem Namen "nameValuePairs" oben in alle json-Objekte eingefügt. Wie kann ich diese @TommySM
nr5

1
Danke dir! Dies löste mein Problem. Jetzt kann ich JSONObject direkt senden, ohne POJOs zu erstellen.
Erfan GLMPR

1
Dies ist die einzige Lösung, die mir geholfen hat, post a null valueeine Eigenschaft im requestBody zu finden, die ansonsten ignoriert wurde.
Shubhral

Ich weiß, ich bin spät dran, aber was steht jsonParams.put("code", some_code);in der dritten Zeile?
Naveen Niraula

81

Wenn Sie in Retrofit2 Ihre Parameter in RAW senden möchten, müssen Sie Skalare verwenden .

füge dies zuerst in dein gradle ein:

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'

Ihre Schnittstelle

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

}

Aktivität

   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) {
    }
}

9
Der Trick hier ist der Skalaradapter vor Gson, andernfalls wird Gson Ihren manuell serialisierten JSON in einen String einschließen.
TWiStErRob

2
jonathan-nolasco-barrientos Sie müssen .baseUrl (ApiInterface.ENDPOINT) in .baseUrl (ApiInterface.URL_BASE) ändern
Milad Ahmadi

2
Wenn Sie verwenden GsonConverterFactory, .toString()ist das nicht notwendig. Sie können erklären , Call<User> getUser(@Body JsonObject body);indem JsonObjectstatt JSONObjectder und übergeben paramObjectdirekt. Es wird gut funktionieren.
Igor de Lorenzi

Hervorragender und einfacher Ansatz. Rettete den Tag
Itai Spector

1
@IgordeLorenzi lösen mein Problem, da ich Spring Boot verwende, um den JSON abzurufen. Nur JsonObject von Gson funktioniert
einwandfrei

44

Verwenden JsonObjectist so wie es ist:

  1. Erstellen Sie Ihre Benutzeroberfläche folgendermaßen:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Erstellen Sie das JsonObject gemäß der jsons-Struktur.

    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. Rufen Sie den Service an:

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

Und das ist es! Meiner persönlichen Meinung nach ist es viel besser, als Pojos zu machen und mit dem Klassenkampf zu arbeiten. Das ist viel sauberer.


1
Was ist, wenn ich keinen bestimmten Wert in der jsonobject-Klasse senden möchte? Welche Annotaion kann ich oben verifizierbar dafür verwenden?
Ali Gürelli

1
Wie Sie im obigen Beispiel sehen können ... JsonObject verwendet als Objekt keine Anotation. In Ihrem Fall, wenn Sie keinen bestimmten Wert senden möchten, können Sie ihn möglicherweise nicht als Eigenschaft hinzufügen ...
superUser

1
Ich meine, ich möchte keinen Wert senden, der in der Klasse deklariert ist. Übrigens habe ich das Problem behoben. Es gab eine Anmerkung für das, was Name ausgesetzt ist.
Ali Gürelli

2
Dies ist der flexibelste Weg. Sie können Ihr json-Objekt konstruieren, selbst wenn Sie nicht wissen, wie viele Felder Sie haben werden, oder selbst wenn Sie nicht wissen, dass sie +1 von mir
heißen

1
Ich erhalte Fehler Service-Methoden können nicht void zurückgeben. für Methode APIServices.signUpUser
Erum

11

Ich mag besonders Jakes Vorschlag für die obigeTypedString Unterklasse . Sie können in der Tat eine Vielzahl von Unterklassen erstellen, die auf den Arten von POST-Daten basieren, die Sie hochfahren möchten, wobei jede ihre eigenen benutzerdefinierten konsistenten Optimierungen enthält.

Sie haben auch die Möglichkeit, Ihren JSON POST-Methoden in Ihrer Retrofit-API eine Header-Annotation hinzuzufügen.

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

… Aber die Verwendung einer Unterklasse ist offensichtlicher selbstdokumentierend.

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

1
Rettete den Tag mit einem klaren Beispiel mit TypedJsonString von JW Vorschlag
miroslavign

10

1) Abhängigkeiten hinzufügen-

 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) Api Handler Klasse machen

    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) Erstellen Sie Bean-Klassen aus Json Schema 2 Pojo

Denken
Sie daran - Zielsprache: Java - Quellentyp: JSON - Anmerkungsstil: Gson - Auswahl Getter und Setter einschließen - Sie können auch Zusätzliche Eigenschaften zulassen auswählen

http://www.jsonschema2pojo.org/

4) Schnittstelle für API-Aufrufe erstellen

    public interface Webservices {

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

}

Wenn Sie Formulardatenparameter haben, fügen Sie die folgende Zeile hinzu

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

Andere Möglichkeit für Formulardatenparameter überprüfen Sie diesen Link

5) Machen Sie JsonObject für die Übergabe an body als Parameter

 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) Rufen Sie Api so an

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

Ich habe festgestellt, dass ein zusammengesetztes Objekt, wenn Sie es als @BodyParameter verwenden, mit den Nachrüstungen nicht gut funktioniert GSONConverter(unter der Annahme, dass Sie dies verwenden). Sie müssen verwenden JsonObjectund nicht, JSONObjectwenn Sie damit arbeiten, es fügt hinzu, NameValueParamsohne ausführlich darüber zu sein - Sie können das nur sehen, wenn Sie eine weitere Abhängigkeit von Protokollierungs-Interceptor und anderen Spielereien hinzufügen.

Was ich am besten gefunden habe, um dies anzugehen, ist die Verwendung RequestBody. Sie wenden Ihr Objekt RequestBodymit einem einfachen API-Aufruf an und starten es. In meinem Fall konvertiere ich eine Karte:

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

und das ist der Aufruf:

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

2
Nun, das hat mir geholfen, nachdem ich über Nacht gegoogelt habe.
W4R10CK

8

Fügen Sie ScalarsConverterFactory zur Nachrüstung hinzu:

in gradle:

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

Ihre Nachrüstung:

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

Ändern Sie den @ Body-Parameter Ihrer Aufrufschnittstelle in String. Vergessen Sie nicht, Folgendes hinzuzufügen @Headers("Content-Type: application/json"):

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

jetzt kannst du raw json posten.


6

Sie können Hashmap verwenden, wenn Sie nicht für jeden API-Aufruf eine Pojo-Klasse erstellen möchten.

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

Und dann so senden

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

4

Nach so viel Mühe festgestellt, dass der grundlegende Unterschied darin besteht, dass Sie den Parameter JsonObjectanstelle von JSONObjectals senden müssen .


Ich habe auch den gleichen Fehler gemacht: p
Mehtab Ahmed

4

Verwenden Sie Folgendes, um json zu senden

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

und an url weitergeben

@Body RequestBody key

4

Basierend auf der Top-Antwort habe ich eine Lösung, um nicht für jede Anfrage POJOs erstellen zu müssen.

Beispiel, ich möchte diesen JSON posten.

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

dann erstelle ich eine gemeinsame Klasse wie diese:

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

Endlich, wenn ich einen Json brauche

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

Die mit Annotation gekennzeichnete Anforderung @Bodykann dann an Retrofit übergeben werden.


4

Wenn Sie keine zusätzlichen Klassen erstellen oder verwenden möchten, JSONObjectkönnen Sie a verwenden HashMap.

Nachrüstschnittstelle:

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

Anruf:

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

Dinge, die erforderlich sind, um rohen JSON in Retrofit zu senden.

1) Stellen Sie sicher, dass Sie den folgenden Header hinzufügen und alle anderen doppelten Header entfernen. Da in den offiziellen Unterlagen von Retrofit ausdrücklich erwähnt wird:

Beachten Sie, dass sich Header nicht gegenseitig überschreiben. Alle gleichnamigen Header werden in die Anfrage aufgenommen.

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

2) a. Wenn Sie eine Konverterfactory verwenden, können Sie Ihren JSON als String, JSONObject, JsonObject und sogar als POJO übergeben. Habe auch geprüft, dass ScalarConverterFactorynicht nur GsonConverterFactoryder Job notwendig ist.

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

2) b. Wenn Sie KEINE Konverterfabrik verwenden, MÜSSEN Sie den RequestBody von okhttp3 verwenden, wie in der Dokumentation von Retrofit angegeben:

Das Objekt wird auch mit einem Konverter konvertiert, der in der Retrofit-Instanz angegeben ist. Wenn kein Konverter hinzugefügt wird, kann nur RequestBody verwendet werden.

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) Erfolg !!


2

Dies ist, was mich für die aktuelle Version von retrofit 2.6.2 funktioniert ,

Zunächst müssen wir der Liste unserer Gradle-Abhängigkeiten einen Skalarkonverter hinzufügen, der die Konvertierung von java.lang.String-Objekten in Text- / Nur-Anforderungskörper übernimmt.

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

Dann müssen wir eine Konverterfabrik an unseren Nachrüstbauer übergeben. Später wird Retrofit mitgeteilt, wie der an den Dienst übergebene @ Body-Parameter konvertiert werden soll.

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

Hinweis: In meinem Nachrüst-Builder habe ich zwei Konverter, Gsonund ScalarsSie können beide verwenden, aber um Json-Körper zu senden, müssen wir uns konzentrieren Scalars, wenn Sie ihn nicht Gsonentfernen müssen

Dann Nachrüstservice mit einem String-Body-Parameter.

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

Erstellen Sie dann den JSON-Body

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

Rufen Sie Ihren Service an

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

2

✅✅✅✅✅✅✅✅✅✅✅✅ Arbeitslösung ✅✅✅✅✅✅✅✅✅✅✅✅

Während der Erstellung OkHttpClient wird dies für die Nachrüstung verwendet.

Fügen Sie einen Interceptor wie diesen hinzu.

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

Jetzt ist Ihre jeder Retrofit Aufruf der URL und Anforderungstext wird geloggt werden in Logcat. Filtern Sie es nach"gsonrequest"


1

Ich habe Folgendes versucht: Wenn Sie Ihre Retrofit-Instanz erstellen, fügen Sie diese Konverterfabrik dem Retrofit-Builder hinzu:

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

1

Ich habe mein Problem basierend auf der Antwort von TommySM gelöst (siehe oben). Aber ich musste mich nicht anmelden, ich habe Retrofit2 zum Testen der https GraphQL API wie folgt verwendet:

  1. Definierte meine BaseResponse-Klasse mithilfe von JSON-Annotationen (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. Definierte die Aufrufprozedur in der Schnittstelle:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Im Testkörper als apicall bezeichnet: Erstellen Sie eine Variable vom Typ MyRequest (z. B. "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

Um die hier gegebenen Antworten klarer zu gestalten, können Sie auf diese Weise die Erweiterungsfunktionen verwenden. Dies ist nur möglich, wenn Sie Kotlin verwenden

Wenn Sie mit com.squareup.okhttp3:okhttp:4.0.1den älteren Methoden der Erzeugung von Objekten von Media und RequestBody sind veraltet und können nicht verwendet werden in Kotlin .

Wenn Sie die Erweiterungsfunktionen verwenden möchten, um ein MediaType- Objekt und ein ResponseBody- Objekt aus Ihren Zeichenfolgen abzurufen, fügen Sie zunächst der Klasse, in der Sie sie verwenden möchten, die folgenden Zeilen hinzu.

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

Auf diese Weise können Sie jetzt direkt ein Objekt von MediaType abrufen

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

Um ein Objekt von RequestBody zu erhalten, konvertieren Sie zuerst das JSONObject, das Sie auf diese Weise an eine Zeichenfolge senden möchten. Sie müssen das mediaType-Objekt an dieses übergeben.

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

0

Ich wollte die Geschwindigkeit von Volley und Nachrüstung für das Senden und Empfangen von Daten vergleichen, die ich unter dem Code geschrieben habe (für den Nachrüstteil).

erste Abhängigkeit:

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

Dann Schnittstelle:

 public interface IHttpRequest {

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

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

und eine Funktion zum Festlegen von Parametern zum Posten von Daten auf dem 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) {

        }
    });

}

Und ich fand Retrofit in meinem Fall schneller als Volley.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.