개조 요청 본문에 원시 JSON 전체를 POST하는 방법은 무엇입니까?


284

이 질문은 이전에 요청되었을 수도 있지만 확실하게 답변되지 않았습니다. Retrofit 요청 본문에 원시 JSON 전체를 정확히 어떻게 게시합니까?

비슷한 질문을 여기에서보십시오 . 아니면이 대답은 양식 URL로 인코딩되어 필드로 전달되어야 한다는 것이 맞 습니까? 내가 연결하려는 서비스가 게시물 본문에서 원시 JSON을 기대하기 때문에 정말로 희망하지 않습니다. JSON 데이터의 특정 필드를 찾도록 설정되지 않았습니다.

나는 단지 restperts로 이것을 명확히하고 싶습니다 . 한 사람이 Retrofit을 사용하지 않겠다고 대답했습니다. 다른 구문은 확실하지 않았습니다. 다른 사람은 그렇다고 할 수 있지만 양식이 URL로 인코딩되어 필드에 배치 된 경우에만 가능하다고 생각합니다 (제 경우에는 허용되지 않습니다). 아니요, Android 클라이언트의 모든 서비스를 다시 코딩 할 수 없습니다. 예, 주요 프로젝트에서 JSON 컨텐츠를 필드 특성 값으로 전달하는 대신 원시 JSON을 게시하는 것이 매우 일반적입니다. 제대로 해보자. 누군가 이것이 어떻게 수행되는지 보여주는 문서 또는 예제를 가리킬 수 있습니까? 또는 수행 할 수없는 이유를 제시하십시오.

업데이트 : 100 % 확실하게 말할 수있는 한 가지. Google 발리에서이 작업을 수행 할 수 있습니다. 내장되어 있습니다. Retrofit에서이 작업을 수행 할 수 있습니까?


7
Jake Wharton의 게시물이 맞습니다! 답변으로 표시하십시오!
edotassi

1
jsonObject를 더 잘 사용할 수 있습니다.
superUser

자세한 답변 futurestud.io/tutorials/…를 위해 RequestBody다음 과 같이 완벽하게 작동합니다RequestBody body = RequestBody.create(MediaType.parse("text/plain"), text);
Kidus Tekeste

답변:


461

@Body주석은 단일 요청 본문을 정의합니다.

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

Retrofit은 기본적으로 Gson을 사용하므로 FooRequest인스턴스는 요청의 유일한 본문으로 JSON으로 직렬화됩니다.

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

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

전화 :

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

다음과 같은 본문을 산출합니다.

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

GSON 워드 프로세서는 훨씬 더 객체 직렬화가 어떻게 작동하는지에 있습니다.

이제 실제로 "raw"JSON을 본문으로 직접 보내려면 (그러나 Gson을 사용하십시오!) 여전히 사용할 수 있습니다 TypedInput:

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

TypedInput 은 "관련된 MIME 유형을 가진 이진 데이터"로 정의됩니다. 위의 선언으로 원시 데이터를 쉽게 보낼 수있는 두 가지 방법이 있습니다.

  1. 원시 바이트와 JSON MIME 유형을 보내 려면 TypedByteArray 를 사용하십시오 .

    String json = "{\"foo\":\"kit\",\"bar\":\"kat\"}";
    TypedInput in = new TypedByteArray("application/json", json.getBytes("UTF-8"));
    FooResponse response = foo.postRawJson(in);
  2. 클래스 를 작성하는 서브 클래스 TypedStringTypedJsonString :

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

    그런 다음 # 1과 유사한 해당 클래스의 인스턴스를 사용하십시오.


5
어쨌든 포조를 만들지 않고 이것을 만들 수 있습니까?
수퍼 유저

28
이것은 개선 2에서 작동하지 않습니다. TypedInput 및 TypedString 클래스가 제거되었습니다.
Ahmed Hegazy

2
@jakewharton TypedString제거 된 이후 우리는 무엇을 할 수 있습니까?
Jared Burrows

12
Retrofit2의 RequestBody경우 원시 바디를 생성하는 데 사용할 수 있습니다 .
bnorm

4
이 예외가 발생합니다java.lang.IllegalArgumentException: Unable to create @Body converter for class MatchAPIRequestBody (parameter #1)
Shajeel Afzal

155

클래스 대신 직접 HashMap<String, Object>매개 변수를 전송 하기 위해 를 사용할 수도 있습니다.

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

2
그때 HashMap <String, Object>와 같은 해시 맵을 만들 수 있습니다. 이는 복잡한 배열과 객체 JSON을 만들 수 있습니다.
학습자

2
어떤 종류의 POJO에 묶이지 않으려는 경우에 좋습니다.
Tim

2
@Nil 당신은 retrofit을 사용하여 json 객체를 보낼 수 없습니다 ... pojo 또는 내 대답을 준수하십시오 ... 이것은 retrofit의 본질입니다. .
학습자

5
나는 IllegalArgumentException: Unable to create @Body converter for java.util.HashMap<java.lang.String, java.lang.Object>Moshi를 얻는다 . 이것이 작동하려면 Gson이 필요하다고 생각합니다
osrl

2
Kotlin을 사용하는 경우 <String, Any>의 해시 맵을 사용하십시오
peresisUser

148

예, 늦었다는 것을 알고 있지만 누군가는 아마 이로부터 혜택을받을 것입니다.

Retrofit2 사용 :

지난 밤에 Volley에서 Retrofit2로 마이그레이션하는이 문제에 부딪 쳤습니다 (OP 상태에서는 이것이 Volley에 내장되어 있음 JsonObjectRequest). Jake의 대답은 Retrofit1.9대한 올바른 대답 이지만 Retrofit2에는 없습니다 TypedString.

내 경우는 송신 요구 Map<String,Object>, 일부는 null 값을 포함 할 수있는을 된 JSONObject로 변환 (즉 비행하지 않을 것이다 @FieldMap,도, 일부 GET 변환 특수 문자 않습니다), 그래서 다음 @bnorms이 힌트를,에 의해 명시된 바와 같이 광장 :

@Body 어노테이션이있는 HTTP 요청 본문으로 사용하도록 오브젝트를 지정할 수 있습니다.

개체는 Retrofit 인스턴스에 지정된 변환기를 사용하여 변환됩니다. 변환기를 추가하지 않으면 RequestBody 만 사용할 수 있습니다.

따라서 이것은 RequestBodyand를 사용하는 옵션입니다 ResponseBody.

인터페이스 @Body에서RequestBody

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

호출 지점 RequestBody에서 MediaType을 나타내는을 만들고 JSONObject를 사용하여 맵을 올바른 형식으로 변환하십시오.

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

이것이 누군가를 돕기를 바랍니다!


위의 우아한 Kotlin 버전으로 나머지 애플리케이션 코드에서 JSON 변환의 매개 변수를 추상화 할 수 있습니다.

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
그래, 나는 이것에 대해 많은 복잡한 반응을보고있다. Retrofit2를 사용하고 있고 발리를하고 싶다면 JsonObjectRequest, 이렇게하면됩니다. 좋은 대답입니다.
VicVu

2
Retrofit은 "nameValuePairs"라는 키를 모든 json 객체의 맨 위에 추가합니다. 나는이 @TommySM를 제거하는 방법
NR5

1
감사합니다! 이것은 내 문제를 해결했다. 이제 POJO를 만들지 않고 JSONObject를 직접 보낼 수 있습니다.
Erfan GLMPR

1
이것은 post a null value그렇지 않으면 requestBody의 속성에 도움이되는 유일한 솔루션입니다 .
Shubhral

나는 늦었다는 것을 알고 있지만 jsonParams.put("code", some_code);세 번째 줄에는 무엇이 있습니까?
Naveen Niraula

81

에서 Retrofit2 당신이 사용해야 원에서 매개 변수를 보내려면, 스칼라을 .

먼저 이것을 gradle에 추가하십시오.

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'

인터페이스

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

}

활동

   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
여기서 트릭은 Gson 이전의 Scalar 어댑터입니다.
TWiStErRob

2
조나단-놀라 스코 - 바리는 당신이 .baseUrl에 .baseUrl (ApiInterface.ENDPOINT) (ApiInterface.URL_BASE) 변경해야
밀라 드 아마디

2
당신이 사용하는 경우 GsonConverterFactory의는 .toString()필요하지 않습니다. 대신을 Call<User> getUser(@Body JsonObject body);사용하여 선언 하고 직접 전달할 수 있습니다. 잘 작동합니다. JsonObjectJSONObjectparamObject
Igor de Lorenzi

1
@IgordeLorenzi는 스프링 부트를 사용하여 gson에서 json 만 JsonObject를 검색하기 때문에 문제를 해결합니다.
haidarvm

1
@IgordeLorenzi 스칼라와 함께 사용하는 것이 JSONObject 또는 JsonObject 중 어느 것이 더 좋은지 차이가 ​​있습니까?
Shukla

44

사용 JsonObject하는 방식은 다음과 같습니다.

  1. 다음과 같이 인터페이스를 작성하십시오.

    public interface laInterfaz{ 
        @POST("/bleh/blah/org")
        void registerPayer(@Body JsonObject bean, Callback<JsonObject> callback);
    }
  2. jsons 구조에 따라 JsonObject를 작성하십시오.

    JsonObject obj = new JsonObject();
    JsonObject payerReg = new JsonObject();
    payerReg.addProperty("crc","aas22");
    payerReg.addProperty("payerDevManufacturer","Samsung");
    obj.add("payerReg",payerReg);
    /*json/*
        {"payerReg":{"crc":"aas22","payerDevManufacturer":"Samsung"}}
    /*json*/
  3. 서비스를 호출하십시오.

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

그리고 그것! 내 개인적인 견해로는, pojos를 만들고 클래스 엉망으로 작업하는 것보다 훨씬 좋습니다. 이것은 훨씬 더 깨끗합니다.


1
jsonobject 클래스에서 specif 값을 보내지 않으려면 어떻게해야합니까? 어떤 Annotaion을 그 위에 사용할 수 있습니까?
Ali Gürelli

1
위의 예제에서 볼 수 있듯이 JsonObject는 객체이므로 주석을 사용하지 않습니다. 귀하의 경우 특정 값을 보내지 않으려면 속성으로 추가하지 않을 수도 있습니다 ...
superUser

1
나는 클래스에서 선언 된 값을 보내고 싶지 않다는 것을 의미합니다. Btw 문제를 해결했습니다. 이름이 노출되는 주석이있었습니다.
Ali Gürelli

2
이것이 가장 유연한 방법입니다. 얼마나 많은 필드를 가질 지 모르거나 나에게서 +1이라는 이름을 모르는 경우에도 json 객체를 생성 할 수 있습니다.
Stoycho Andreev

1
im getting error 서비스 메소드가 void를 리턴 할 수 없습니다. 방법 APIServices.signUpUser에 대한
Erum

11

특히 TypedString하위 클래스 에 대한 Jake의 제안이 마음에 듭니다 . 푸시 업하려는 POST 데이터의 종류에 따라 다양한 서브 클래스를 만들 수 있으며, 각각 고유 한 맞춤 조정 세트가 있습니다.

Retrofit API에서 JSON POST 메소드에 헤더 주석을 추가 할 수도 있습니다…

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

…하지만 서브 클래스를 사용하는 것이 더 분명한 자체 문서화입니다.

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

1
JW 제안에서 TypedJsonString를 사용하여 명확한 예제를 하루에 저장
miroslavign

10

1) 의존성 추가-

 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 핸들러 클래스 만들기

    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) Json schema 2 pojo에서 bean 클래스 만들기

기억
- 대상 언어 : 자바 -source 유형 : JSON -Annotation 스타일 : GSON이 -를 선택하여 getter 및 setter를 포함 당신이 선택할 수 있습니다 - 또한 추가 속성을 허용

http://www.jsonschema2pojo.org/

4) api 호출 인터페이스 만들기

    public interface Webservices {

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

}

양식 데이터 매개 변수가 있으면 아래 행을 추가하십시오.

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

양식 데이터 매개 변수를위한 다른 방법은이 링크를 확인 하십시오.

5) JsonObject를 매개 변수로 본문에 전달합니다.

 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) Call Api 이렇게

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

복합 객체를 @Body매개 변수 로 사용할 때 Retrofit과 잘 작동하지 않는다는 것을 알았 습니다 (이를 GSONConverter사용한다고 가정 할 때). 작업 할 때 사용 JsonObject하지 말아야 JSONObject하며 그것에 NameValueParams대해 자세하게 설명하지 않고 로깅 인터셉터 및 다른 shenanigans의 다른 종속성을 추가하는 경우에만 볼 수 있습니다.

그래서 이것을 해결하는 가장 좋은 방법은을 사용하는 것 RequestBody입니다. RequestBody간단한 API 호출로 객체를 켜고 시작합니다. 제 경우에는지도를 변환하고 있습니다.

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

그리고 이것은 전화입니다.

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

2
밤새 인터넷 검색 후 도움이되었습니다.
W4R10CK

8

개조에 ScalarsConverterFactory를 추가하십시오.

gradle에서 :

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

당신의 개조 :

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

호출 인터페이스 @Body 매개 변수를 String으로 변경하십시오 @Headers("Content-Type: application/json").

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

이제 원시 json을 게시 할 수 있습니다.


6

모든 API 호출에 대해 pojo 클래스를 작성하지 않으려는 경우 해시 맵을 사용할 수 있습니다.

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

그리고 이렇게 보내

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

5

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

그리고 그것을 URL로 전달하십시오.

@Body RequestBody key

4

많은 노력을 기울인 후 기본 차이점은 매개 변수로 JsonObject대신 보내야한다는 것입니다 JSONObject.


나는 또한 같은 실수를하고 있었다 : p
Mehtab Ahmed

4

최고의 답변을 바탕으로 모든 요청에 ​​대해 POJO를 만들 필요가없는 솔루션이 있습니다.

예를 들어이 JSON을 게시하고 싶습니다.

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

그런 다음 다음과 같은 공통 클래스를 만듭니다.

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

마지막으로 JSON이 필요할 때

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

주석으로 표시된 요청은 @BodyRetrofit으로 전달 될 수 있습니다.


4

추가 클래스를 만들거나 사용하지 않으려면을 사용할 JSONObject수 있습니다 HashMap.

개조 인터페이스 :

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

요구:

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

Retrofit에서 원시 JSON을 전송하는 데 필요한 사항.

1) 다음 헤더를 추가하고 다른 중복 헤더를 제거하십시오. Retrofit의 공식 문서에서 그들은 구체적으로 언급했습니다.

헤더는 서로 덮어 쓰지 않습니다. 이름이 같은 모든 헤더가 요청에 포함됩니다.

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

2) a. 변환기 팩토리를 사용하는 경우 json을 String, JSONObject, JsonObject 및 POJO로 전달할 수 있습니다. 또한 확인 만해도 작업이 ScalarConverterFactory필요한 것은 아닙니다 GsonConverterFactory.

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

2) b. 컨버터 팩토리를 사용하지 않는 경우 okhttp3의 RequestBody를 Retrofit의 설명서에 따라 사용해야합니다.

개체는 Retrofit 인스턴스에 지정된 변환기를 사용하여 변환됩니다. 변환기를 추가하지 않으면 RequestBody 만 사용할 수 있습니다.

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

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

3) 성공 !!


2

이는 현재 버전의 저를 작동하는 것입니다 retrofit 2.6.2 ,

우선 Gradle 종속성 목록에 Scalars Converter를 추가해야합니다. Gradle 종속성은 java.lang.String 객체를 text / plain request body로 변환하는 것을 처리합니다.

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

그런 다음 변환기 팩토리를 Retrofit 빌더로 전달해야합니다. 나중에 Retrofit에 서비스에 전달 된 @Body 매개 변수를 변환하는 방법을 알려줍니다.

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

참고 : 내 개조에서 나는 두 개의 컨버터가 건축업자 GsonScalars당신은 그들 모두를 사용할 수 있지만 우리가 초점을 맞출 필요가 JSON 본문을 보낼 Scalars필요하지 않은 경우 그래서 Gson그것을 제거

그런 다음 String body 매개 변수를 사용하여 Retrofit 서비스를 제공하십시오.

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

그런 다음 JSON 본문을 만듭니다.

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

서비스 요청

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

2

Solution 작업 솔루션 ✅✅✅✅✅✅✅✅✅✅✅✅

OkHttpClient그것을 만드는 동안 Retrofit에 사용됩니다.

이와 같은 인터셉터를 추가하십시오.

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

이제 모든 Retrofit 통화의 URL 및 요청 본문이 로그인 됩니다 Logcat. 로 필터링"gsonrequest"


1

나는 이것을 시도했다 : Retrofit 인스턴스를 만들 때이 변환기 팩토리를 개조 빌더에 추가하십시오.

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

1

TommySM 답변을 기반으로 내 문제를 해결했습니다 (이전 참조). 그러나 로그인 할 필요가 없었으며 Retrofit2를 사용하여 https GraphQL API를 다음과 같이 테스트했습니다.

  1. json 주석 (import jackson.annotation.JsonProperty)을 사용하여 BaseResponse 클래스를 정의했습니다.

    public class MyRequest {
        @JsonProperty("query")
        private String query;
    
        @JsonProperty("operationName")
        private String operationName;
    
        @JsonProperty("variables")
        private String variables;
    
        public void setQuery(String query) {
            this.query = query;
        }
    
        public void setOperationName(String operationName) {
            this.operationName = operationName;
        }
    
        public void setVariables(String variables) {
            this.variables = variables;
        }
    }
  2. 인터페이스에서 호출 절차를 정의했습니다.

    @POST("/api/apiname")
    Call<BaseResponse> apicall(@Body RequestBody params);
  3. 테스트 본문에서 apicall 호출 : MyRequest 유형의 변수 (예 : "myLittleRequest")를 작성하십시오.

    Map<String, Object> jsonParams = convertObjectToMap(myLittleRequest);
    RequestBody body = 
         RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),
                        (new JSONObject(jsonParams)).toString());
    response = hereIsYourInterfaceName().apicall(body).execute();

0

여기에 주어진 답변을 더 명확하게하기 위해 확장 기능을 사용하는 방법입니다. Kotlin을 사용하는 경우에만 해당

MediaTypeRequestBody의com.squareup.okhttp3:okhttp:4.0.1 객체를 생성하는 이전 방법을 사용 하는 경우 더 이상 사용되지 않으며 Kotlin 에서 사용할 수 없습니다 .

확장 함수를 사용 하여 문자열에서 MediaType 객체와 ResponseBody 객체 를 얻으려면 먼저 다음 줄을 사용하려는 클래스에 추가하십시오.

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

이런 식 으로 MediaType 의 객체를 직접 얻을 수 있습니다.

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

의 객체를 얻으려면 RequestBody 먼저 문자열로 보내려는 JSONObject를 이런 식으로 변환하십시오. mediaType 객체를 전달해야합니다.

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

0

아래 코드를 작성하여 데이터를주고받는 데있어 발리 속도와 개장 속도를 비교하고 싶었습니다 (개장 부분).

첫 번째 의존성 :

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

그런 다음 인터페이스 :

 public interface IHttpRequest {

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

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

서버에 데이터를 게시하는 매개 변수를 설정하는 기능 (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) {

        }
    });

}

제 경우에는 발리보다 Retrofit이 더 빠릅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.