Прочитать текстовый ответ с сервера с помощью Retrofit - PullRequest
3 голосов
/ 14 июля 2020

Я работаю над приложением, которое использует Retrofit для сетевых операций. В его нынешнем виде все работает хорошо с GsonConverterFactory, обрабатывающим сериализацию. Вот как я настраиваю Retrofit

Retrofit.Builder()
        .baseUrl("<base url>") 
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()

Теперь мне нужно подключиться к устаревшей службе, которая возвращает контент в формате text/plain; charset=utf-8. Вот интерфейс Retrofit

@GET("https://<domain>/<endpoint>?Type=Query")
suspend fun callStatus(@Query("userId") id: Int): Response<String>

Это вернет статус вызова для действительного пользователя. Например, если пользователь действителен и есть статус, он возвращает «Активный» в виде обычного текста. Если действующего пользователя нет, он возвращает код ошибки # 1005

Я мог бы добавить фабрику настраиваемых преобразователей, как это (найдено в Интернете)

final class StringConverterFactory implements Converter.Factory {
    private StringConverterFactory() {}

    public static StringConverterFactory create() {
        return new StringConverterFactory();
    }

    @Override
    public Converter<String> get(Type type) {
        Class<?> cls = (Class<?>) type;
        if (String.class.isAssignableFrom(cls)) {
            return new StringConverter();
        }
        return null;
    }

    private static class StringConverter implements Converter<String> {
        private static final MediaType PLAIN_TEXT = MediaType.parse("text/plain; charset=UTF-8");

        @Override
        public String fromBody(ResponseBody body) throws IOException {
            return new String(body.bytes());
        }

        @Override
        public RequestBody toBody(String value) {
            return RequestBody.create(PLAIN_TEXT, convertToBytes(value));
        }

        private static byte[] convertToBytes(String string) {
            try {
                return string.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Но я не видел это имеет значение. Кроме того, он мог замаскировать JSON как обычный текст и сломать все существующие службы. Есть ли лучший способ справиться с этим сценарием? Я подумал о том, чтобы иметь отдельный экземпляр модификации для простого текста, хотя и немного грязного. У вас есть другие предложения / решения?

Отредактировано

Заголовок ответа содержит тип содержимого как Content-Type: text/plain; charset=utf-8

Фактический ответ для действительного пользователя

Active

Фактический ответ для недопустимого пользователя

#1005

Ответы [ 3 ]

6 голосов
/ 17 июля 2020

Обновление

Порядок, в котором вы регистрируете фабрики конвертеров, имеет значение. ScalarsConverterFactory должен быть первым.

это должно быть возможно, добавив ScalarsConverterFactory при построении объекта Retrofit. Это можно сделать вместе с другими конвертерами json, например

Retrofit.Builder()
        .baseUrl("<base url>") 
        .client(client)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build()

После этого вы сможете получать ответы в виде открытого текста.

Вероятно, вам нужно добавить это в свои зависимости как хорошо:

implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
0 голосов
/ 17 июля 2020

Вот как я получаю ответ в виде простого текста (используя Java не Kotlin).

Step One

в вашем gradle (Модуль);

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

Шаг второй

Создание интерфейса

public interface MyInterface {
    @GET("something.php")
    Call<String> getData(@Query("id") String id,
                         @Query("name") String name);
}

Шаг третий

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://example.com")
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

MyInterface myInterface = retrofit.create(MyInterface.class);
Call<String> call = myInterface.getData("id","myname");
call.enqueue(new Callback<String>() {
                    @Override
                    public void onResponse(Call<String> call, Response<String> response) {
                        String plain_text_response = response.body();
                    }

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

                    }
                });
0 голосов
/ 14 июля 2020

Вам не нужно использовать собственную реализацию Converter.Factory, вы можете просто использовать

// your coroutine context
    val response = callStatus(userId)
    if(response.isSuccessful){
        val plainTextContent = response.body()
        // handle plainText
    } else {
     //TODO: Handle error
    }
 //...
...