Bagaimana cara mengirim seluruh JSON ke dalam tubuh permintaan Retrofit?

285

Pertanyaan ini mungkin telah ditanyakan sebelumnya tetapi tidak, itu tidak dijawab secara definitif. Bagaimana tepatnya satu posting seluruh JSON mentah di dalam tubuh permintaan Retrofit?

Lihat pertanyaan serupa di sini . Atau apakah jawaban ini benar bahwa harus berupa url yang disandikan dan diteruskan sebagai bidang ? Saya benar-benar berharap tidak, karena layanan yang saya sambungkan hanya mengharapkan JSON mentah di badan pos. Mereka tidak diatur untuk mencari bidang tertentu untuk data JSON.

Saya hanya ingin mengklarifikasi ini dengan restperts sekali dan untuk semua. Satu orang menjawab untuk tidak menggunakan Retrofit. Yang lain tidak yakin dengan sintaksisnya. Lain berpikir ya itu bisa dilakukan tetapi hanya jika bentuknya disandikan url dan ditempatkan di lapangan (itu tidak dapat diterima dalam kasus saya). Tidak, saya tidak bisa membuat ulang kode semua layanan untuk klien Android saya. Dan ya, sangat umum dalam proyek-proyek besar untuk mengirim JSON mentah alih-alih menyerahkan konten JSON sebagai nilai properti bidang. Mari kita lakukan dengan benar dan melanjutkan. Dapatkah seseorang menunjuk pada dokumentasi atau contoh yang menunjukkan bagaimana hal ini dilakukan? Atau berikan alasan yang valid mengapa itu bisa / tidak boleh dilakukan.

UPDATE: Satu hal yang bisa saya katakan dengan kepastian 100%. Anda BISA melakukan ini di Volley Google. Itu sudah terpasang. Bisakah kita melakukan ini di Retrofit?

pengguna3243335
sumber
7
Posisi Jake Wharton benar! Tandai sebagai jawaban!
edotassi
1
Anda mungkin menggunakan jsonObject lebih baik.
superUser
bekerja sempurna dengan RequestBodyseperti ini -> RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);untuk jawaban terinci futurestud.io/tutorials/…
Kidus Tekeste

Jawaban:

461

The @Bodypenjelasan mendefinisikan permintaan badan tunggal.

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

Karena Retrofit menggunakan Gson secara default, FooRequestinstans akan diserialisasi sebagai JSON sebagai satu-satunya badan permintaan.

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

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

Panggilan dengan:

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

Akan menghasilkan tubuh berikut:

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

Dokumen Gson memiliki lebih banyak tentang cara kerja serialisasi objek.

Sekarang, jika Anda benar-benar ingin mengirim JSON "mentah" sebagai tubuh sendiri (tapi tolong gunakan Gson untuk ini!) Anda masih dapat menggunakan TypedInput:

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

TypedInput didefinisikan sebagai "Data biner dengan tipe mime terkait." Ada dua cara untuk dengan mudah mengirim data mentah dengan deklarasi di atas:

  1. Gunakan TypedByteArray untuk mengirim byte mentah dan tipe mime JSON:

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. Subclass TypedString untuk membuat TypedJsonStringkelas:

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

    Dan kemudian gunakan instance dari kelas yang mirip dengan # 1.

Jake Wharton
sumber
5
Sangat baik, bagaimanapun, apakah ada cara untuk membuat ini tanpa membuat pojo?
super Pengguna
28
Ini tidak bekerja pada retrofit 2. Kelas TypedInput dan TypedString telah dihapus.
Ahmed Hegazy
2
@jakewharton Apa yang bisa kita lakukan TypedStringkarena sudah dihapus?
Jared Burrows
12
Untuk Retrofit2, Anda bisa menggunakannya RequestBodyuntuk membuat tubuh mentah.
Bnorm
4
Saya mendapatkan pengecualian inijava.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal
156

Sebagai pengganti kelas kita juga dapat langsung menggunakan HashMap<String, Object>untuk mengirim parameter tubuh misalnya

interface Foo {
  @POST("/jayson")
  FooResponse postJson(@Body HashMap<String, Object> body);
}
pelajar
sumber
2
Pada saat itu Anda dapat membuat peta Hash seperti HashMap <String, Object>, dapat dimungkinkan untuk membuat array dan objek JSON yang agak rumit.
pelajar
2
Ini bagus sekali jika Anda tidak ingin terikat dengan POJO.
Tim
2
@Nil Anda tidak dapat mengirim objek json dengan menggunakan retrofit ... Anda mematuhi pojo atau jawaban saya ... ini adalah sifat retrofit.Jika Anda ingin lebih lanjut tentang ini, tanyakan Jake Wharton ia adalah seorang pengembang retrofit, jawabannya juga tersedia dengan pojo .
pelajar
5
Saya dapatkan IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>dengan Moshi. Saya pikir Gson diperlukan agar ini berfungsi
osrl
2
Jika menggunakan Kotlin, gunakan hashmap <String, Any>
peresisUser
148

Ya saya tahu ini sudah terlambat, tetapi seseorang mungkin akan mendapat manfaat dari ini.

Menggunakan Retrofit2:

Saya menemukan masalah ini tadi malam bermigrasi dari Volley ke Retrofit2 (dan seperti yang dinyatakan OP, ini dibangun langsung ke Volley bersama JsonObjectRequest), dan meskipun jawaban Jake adalah yang benar untuk Retrofit1.9 , Retrofit2 tidak punya TypedString.

Kasing saya membutuhkan pengiriman Map<String,Object>yang dapat berisi beberapa nilai nol, dikonversi ke JSONObject (yang tidak akan terbang @FieldMap, begitu pula karakter khusus, beberapa dikonversi), jadi ikuti petunjuk @bnorms, dan seperti yang dinyatakan oleh Square :

Objek dapat ditentukan untuk digunakan sebagai badan permintaan HTTP dengan anotasi @Body.

Objek juga akan dikonversi menggunakan konverter yang ditentukan pada instance Retrofit. Jika tidak ada konverter yang ditambahkan, hanya RequestBody yang dapat digunakan.

Jadi ini adalah opsi menggunakan RequestBodydan ResponseBody:

Di antarmuka Anda gunakan @BodydenganRequestBody

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

Di titik panggilan Anda buat RequestBody, nyatakan itu adalah MediaType, dan gunakan JSONObject untuk mengonversi Peta Anda ke format yang tepat:

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

Semoga ini Membantu siapa pun!


Versi Kotlin yang elegan di atas, untuk memungkinkan abstrak parameter dari konversi JSON di sisa kode aplikasi Anda:

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

}
TommySM
sumber
2
Ya saya melihat banyak tanggapan rumit untuk ini. Jika Anda menggunakan Retrofit2 dan ingin melakukan voli JsonObjectRequest, yang perlu Anda lakukan adalah ini. Jawaban yang bagus.
VicVu
2
Retrofit menambahkan kunci bernama "nameValuePairs" ke atas semua objek json. Bagaimana saya bisa menghapus @TommySM ini
NR5
1
Terima kasih! Ini menyelesaikan masalah saya. Sekarang saya dapat mengirim JSONObject secara langsung tanpa membuat POJO.
Erfan GLMPR
1
Ini adalah satu-satunya solusi yang membantu saya ke post a null valueproperti di requestBody yang sebaliknya diabaikan.
Shubhral
Saya tahu saya terlambat tetapi apa yang ada jsonParams.put("code", some_code);di baris ketiga?
Naveen Niraula
81

Di Retrofit2 , Saat Anda ingin mengirim parameter Anda secara baku, Anda harus menggunakan Skalar .

pertama tambahkan ini di gradle Anda:

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'

Antarmuka Anda

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

}

Aktivitas

   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", "[email protected]");
            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) {
    }
}
Jonathan Nolasco Barrientos
sumber
10
Kuncinya di sini adalah adaptor Scalar sebelum Gson, jika tidak Gson akan membungkus JSON serialisasi Anda secara manual dalam sebuah String.
TWiStErRob
2
jonathan-nolasco-barrientos Anda harus mengubah .baseUrl (ApiInterface.ENDPOINT) menjadi .baseUrl (ApiInterface.URL_BASE)
Milad Ahmadi
2
Ketika Anda menggunakan GsonConverterFactory, .toString()itu tidak perlu. Anda dapat mendeklarasikan Call<User> getUser(@Body JsonObject body);menggunakan JsonObjectalih-alih JSONObjectdan meneruskan paramObjectsecara langsung. Ini akan bekerja dengan baik.
Igor de Lorenzi
1
@IgordeLorenzi menyelesaikan masalah saya, karena saya menggunakan spring boot untuk mengambil json saja. JsonObject dari gson works fine
haidarvm
1
@IgordeLorenzi Apakah ada perbedaan mana yang lebih baik JSONObject atau JsonObject untuk digunakan dengan skalar.
Sumit Shukla
44

Penggunaan JsonObjectadalah sebagaimana adanya:

  1. Buat antarmuka Anda seperti ini:

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. Jadikan JsonObject sesuai dengan struktur 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. Panggil layanan:

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

Dan itu! Menurut pendapat pribadi saya, ini jauh lebih baik daripada membuat pojo dan bekerja dengan kekacauan kelas. Ini jauh lebih bersih.

pengguna super
sumber
1
Bagaimana jika saya tidak ingin mengirim nilai tertentu di kelas jsonobject. annotaion mana yang dapat saya gunakan di atas yang dapat diverifikasi untuk itu?
Ali Gürelli
1
Seperti yang Anda lihat contoh di atas ... JsonObject karena ini adalah objek, tidak menggunakan anotasi apa pun. Dalam kasus Anda jika Anda tidak ingin mengirim nilai tertentu, Anda mungkin tidak menambahkannya sebagai properti ...
superUser
1
Maksud saya, saya tidak ingin mengirim nilai yang dideklarasikan di kelas. Tapi saya memperbaiki masalahnya. Ada anotasi untuk nama yang terbuka.
Ali Gürelli
2
Ini adalah cara yang paling fleksibel. Anda dapat membangun objek json Anda bahkan jika Anda tidak tahu berapa banyak bidang yang akan Anda miliki atau bahkan jika Anda tidak tahu mereka memberi nama +1 dari saya
Stoycho Andreev
1
saya mendapatkan kesalahan. Metode layanan tidak dapat mengembalikan batal. untuk metode APIServices.signUpUser
Erum
11

Saya terutama menyukai saran Jake tentang TypedStringsubkelas di atas . Anda memang dapat membuat berbagai subclass berdasarkan jenis data POST yang Anda rencanakan untuk ditingkatkan, masing-masing dengan set kustom tweak yang konsisten.

Anda juga memiliki opsi untuk menambahkan anotasi header ke metode JSON POST Anda di Retrofit API Anda ...

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

... tetapi menggunakan subkelas lebih jelas mendokumentasikan diri.

@POST("/json/foo/bar")
Response fubar( @Body TypedJsonString jsonBody ) ;
zerobandwidth
sumber
1
Menyelamatkan hari dengan contoh yang jelas menggunakan TypedJsonString dari saran JW
miroslavign
10

1) Tambahkan dependensi-

 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) membuat kelas 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) membuat kelas kacang dari Json schema 2 pojo

Ingat
-Target bahasa: Java -Jenis sumber: JSON-Gaya catatan: Gson -Pilih Sertakan getter dan setter -juga Anda dapat memilih Izinkan properti tambahan

http://www.jsonschema2pojo.org/

4) membuat antarmuka untuk panggilan api

    public interface Webservices {

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

}

jika Anda memiliki parameter form-data kemudian tambahkan baris di bawah ini

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

Cara lain untuk parameter formulir-data periksa tautan ini

5) membuat JsonObject untuk diteruskan ke tubuh sebagai 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) Panggil Api Seperti ini

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

Saya menemukan bahwa ketika Anda menggunakan objek majemuk sebagai @Bodyparams, itu tidak dapat bekerja dengan baik dengan Retrofit GSONConverter(dengan asumsi Anda menggunakannya). Anda harus menggunakan JsonObjectdan tidak JSONObjectketika bekerja dengan itu, ia menambahkan NameValueParamstanpa bertele-tele tentang itu - Anda hanya dapat melihat bahwa jika Anda menambahkan ketergantungan lain dari penebang pencegat, dan shenanigans lainnya.

Jadi apa yang saya temukan pendekatan terbaik untuk mengatasi ini adalah menggunakan RequestBody. Anda mengubah objek Anda RequestBodydengan panggilan api sederhana dan meluncurkannya. Dalam kasus saya, saya mengonversi peta:

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

dan inilah panggilannya:

 @POST("openUsvDeal")
fun openUsvDeal(
        @Body params: RequestBody,
        @Query("timestamp") timeStamp: Long,
        @Query("appid") appid: String = Constants.APP_ID,
): Call<JsonObject>
peresisUser
sumber
2
Nah ini membantu saya setelah googling semalaman.
W4R10CK
8

Tambahkan ScalarsConverterFactory ke retrofit:

dalam gradle:

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

retrofit Anda:

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

ubah parameter antarmuka panggilan @Body ke String, jangan lupa tambahkan @Headers("Content-Type: application/json"):

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

sekarang Anda dapat memposting json mentah.

bintang-ali
sumber
6

Anda dapat menggunakan hashmap jika Anda tidak ingin membuat kelas pojo untuk setiap panggilan API.

HashMap<String,String> hashMap=new HashMap<>();
        hashMap.put("email","[email protected]");
        hashMap.put("password","1234");

Dan kemudian kirim seperti ini

Call<JsonElement> register(@Body HashMap registerApiPayload);
jatin rana
sumber
5

gunakan berikut untuk mengirim 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());

dan berikan ke url

@Body RequestBody key
Mahesh Pandit
sumber
4

Setelah begitu banyak upaya, ditemukan bahwa perbedaan mendasar adalah Anda perlu mengirim JsonObjectbukan JSONObjectparameter.

umair151
sumber
Saya juga melakukan kesalahan yang sama: p
Mehtab Ahmed
4

Berdasarkan jawaban teratas, saya punya solusi untuk tidak harus membuat POJO untuk setiap permintaan.

Contoh, saya ingin memposting JSON ini.

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

lalu, saya membuat kelas umum seperti ini:

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

Akhirnya, ketika saya membutuhkan json

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

Permintaan yang ditandai anotasi @Bodykemudian dapat diteruskan ke Retrofit.

wjploop
sumber
4

Jika Anda tidak ingin membuat kelas atau penggunaan tambahan, JSONObjectAnda dapat menggunakan a HashMap.

Antarmuka retrofit:

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

Panggilan:

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

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

Hal-hal yang diperlukan untuk mengirim json mentah di Retrofit.

1) Pastikan untuk menambahkan header berikut dan menghapus header duplikat lainnya. Karena, pada dokumentasi resmi Retrofit mereka secara spesifik menyebutkan-

Perhatikan bahwa tajuk tidak saling menimpa. Semua tajuk dengan nama yang sama akan dimasukkan dalam permintaan.

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

2) a. Jika Anda menggunakan pabrik konverter, Anda dapat melewatkan json Anda sebagai sebuah String, JSONObject, JsonObject dan bahkan POJO. Juga telah memeriksa, ScalarConverterFactorytidak perlu hanya GsonConverterFactorymelakukan pekerjaan.

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

2) b. Jika Anda TIDAK menggunakan pabrik konverter apa pun maka Anda HARUS menggunakan RequestBody okhttp3 seperti yang dikatakan dokumentasi Retrofit-

Objek juga akan dikonversi menggunakan konverter yang ditentukan pada instance Retrofit. Jika tidak ada konverter yang ditambahkan, hanya RequestBody yang dapat digunakan.

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

Darshan Miskin
sumber
2

Inilah yang bekerja saya untuk versi retrofit 2.6.2 saat ini ,

Pertama-tama, kita perlu menambahkan Scalars Converter ke daftar dependensi Gradle kita, yang akan mengurusi konversi java.lang. Objek-objek tring ke teks / badan permintaan polos,

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

Kemudian, kita perlu melewati pabrik konverter ke pembuat Retrofit kita. Nantinya akan memberi tahu Retrofit cara mengonversi parameter @Body yang dilewatkan ke layanan.

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

Catatan: Di pembangun retrofit saya, saya memiliki dua konverter Gsondan ScalarsAnda dapat menggunakan keduanya tetapi untuk mengirim Json body kita perlu fokus Scalarsjadi jika Anda tidak perlu Gsonmenghapusnya

Kemudian Retrofit service dengan parameter String body.

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

Kemudian buat tubuh JSON

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

Hubungi layanan Anda

RetrofitService.myApi.saveUser(user.toString())
Jimale Abdi
sumber
2

✅✅✅✅✅✅✅✅✅✅✅✅ Solusi Kerja ✅✅✅✅✅✅✅✅✅✅✅✅

Saat membuat OkHttpClient itu akan digunakan untuk Retrofit.

tambahkan Interceptor seperti ini.

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

Sekarang Anda setiap Retrofit call URL dan permintaan tubuh akan login di Logcat. Saring dengan"gsonrequest"

erluxman
sumber
1

Saya mencoba ini: Ketika Anda membuat instance Retrofit Anda, tambahkan pabrik konverter ini ke pembuat retrofit:

gsonBuilder = new GsonBuilder().serializeNulls()     
your_retrofit_instance = Retrofit.Builder().addConverterFactory( GsonConverterFactory.create( gsonBuilder.create() ) )
Arman Ramezanzadeh
sumber
1

Memecahkan masalah saya berdasarkan jawaban TommySM (lihat sebelumnya). Tetapi saya tidak perlu melakukan login, saya menggunakan Retrofit2 untuk menguji https GraphQL API seperti ini:

  1. Menentukan kelas BaseResponse saya dengan bantuan anotasi 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. Menetapkan prosedur panggilan di antarmuka:

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. Disebut apicall di badan pengujian: Buat variabel tipe MyRequest (misalnya "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();
Natalya Shatalova
sumber
0

Untuk lebih jelasnya pada jawaban yang diberikan di sini, ini adalah bagaimana Anda dapat menggunakan fungsi ekstensi. Ini hanya jika Anda menggunakan Kotlin

Jika Anda menggunakan com.squareup.okhttp3:okhttp:4.0.1metode lama dalam membuat objek MediaType dan RequestBody telah usang dan tidak dapat digunakan di Kotlin .

Jika Anda ingin menggunakan fungsi ekstensi untuk mendapatkan objek MediaType dan objek ResponseBody dari string Anda, pertama-tama tambahkan baris berikut ke kelas di mana Anda ingin menggunakannya.

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

Anda sekarang dapat secara langsung mendapatkan objek MediaType dengan cara ini

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

Untuk mendapatkan objek dari RequestBody, konversikan dulu JSONObject yang ingin Anda kirim ke string dengan cara ini. Anda harus meneruskan objek mediaType ke sana.

val requestBody = myJSONObject.toString().toRequestBody(mediaType)
Devenom
sumber
0

Saya ingin membandingkan kecepatan voli dan retrofit untuk mengirim dan menerima data yang saya tulis di bawah kode (untuk bagian retrofit)

ketergantungan pertama:

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

Lalu antarmuka:

 public interface IHttpRequest {

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

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

dan fungsi untuk mengatur parameter untuk mengirim data ke server (Dalam 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) {

        }
    });

}

Dan saya menemukan Retrofit lebih cepat daripada voli dalam kasus saya.

Liam
sumber