如何使用Retrofit和Kotlin协程下载PDF文件? [英] How to download PDF file with Retrofit and Kotlin coroutines?

查看:1095
本文介绍了如何使用Retrofit和Kotlin协程下载PDF文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了诸如>如何使用翻新库?,它们使用@Streaming和RxJava/回调.

I saw topics like How to download file in Android using Retrofit library?, they use @Streaming and RxJava / callbacks.

我有Kotlin,协程,翻新版2.6.0和类似 https://stackoverflow.com/a/56473934/2914140的查询:

I have Kotlin, coroutines, Retrofit 2.6.0 and queries like in https://stackoverflow.com/a/56473934/2914140:

@FormUrlEncoded
@Streaming
@POST("export-pdf/")
suspend fun exportPdf(
    @Field("token") token: String
): ExportResponse

我有一个改造客户:

retrofit = Retrofit.Builder()
    .baseUrl(SERVER_URL)
    .client(okHttpClient)
    .build()

service = retrofit.create(Api::class.java)

如果令牌参数正确,查询将返回PDF文件:

If a token parameter is right, the query returns PDF file:

%PDF-1.4
%����
...

如果错了,它将返回带有错误描述的JSON:

If it is wrong, it will return JSON with error description:

{
    "success": 0,
    "errors": {
        "message": "..."
    }
}

因此,ExportResponse是一个包含JSON字段POJO的数据类.

So, ExportResponse is a data class containing JSON fields, POJO.

我无法使用

Response response = restAdapter.apiRequest();

try {
    //you can now get your file in the InputStream
    InputStream is = response.getBody().in();
} catch (IOException e) {
    e.printStackTrace();
}

因为ExportResponse是数据类,所以val response: ExportResponse = interactor.exportPdf(token)将返回数据,而不是Retrofit对象.

because ExportResponse is a data class, so val response: ExportResponse = interactor.exportPdf(token) will return data, not Retrofit object.

推荐答案

您可以将exportPdf的返回类型更改为Call<ResponseBody>,然后检查响应代码.如果可以,请以流的形式读取正文.如果不是,请尝试反序列化ExportResponse. 我猜看起来像这样:

You can change the return type of exportPdf to Call<ResponseBody> and then check the response code. If it's ok then read the body as a stream. If it's not then try to deserialize ExportResponse. It will look something like this I guess:

val response = restAdapter.apiRequest().execute()
if (response.isSuccessful) {
    response.body()?.byteStream()//do something with stream
} else {
    response.errorBody()?.string()//try to deserialize json from string
}

更新

这是我的考试的完整清单:

Here is a complete listing of my test:

import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.http.GET
import retrofit2.http.Url
import java.io.File
import java.io.InputStream

fun main() {
    val queries = buildQueries()
    check(queries, "http://127.0.0.1:5000/error")
    check(queries, "http://127.0.0.1:5000/pdf")
}

private fun check(queries: Queries, url: String) {
    val response = queries.exportPdf(HttpUrl.get(url)).execute()
    if (response.isSuccessful) {
        response.body()?.byteStream()?.saveToFile("${System.currentTimeMillis()}.pdf")
    } else {
        println(response.errorBody()?.string())
    }
}

private fun InputStream.saveToFile(file: String) = use { input ->
    File(file).outputStream().use { output ->
        input.copyTo(output)
    }
}

private fun buildRetrofit() = Retrofit.Builder()
    .baseUrl("http://127.0.0.1:5000/")
    .client(OkHttpClient())
    .build()

private fun buildQueries() = buildRetrofit().create(Queries::class.java)

interface Queries {
    @GET
    fun exportPdf(@Url url: HttpUrl): Call<ResponseBody>
}

这是用Flask构建的简单服务器:

and here is simple sever built with Flask:

from flask import Flask, jsonify, send_file

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello, World!'


@app.route('/error')
def error():
    response = jsonify(error=(dict(body='some error')))
    response.status_code = 400
    return response


@app.route('/pdf')
def pdf():
    return send_file('pdf-test.pdf')

对我来说一切正常

更新2

好像您必须在Api中编写以下代码:

Looks like you have to write this in your Api:

@FormUrlEncoded
@Streaming // You can also comment this line.
@POST("export-pdf/")
fun exportPdf(
    @Field("token") token: String
): Call<ResponseBody>

这篇关于如何使用Retrofit和Kotlin协程下载PDF文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆