【问题标题】:"No transformation found: class io.ktor.utils.io.ByteChannelNative" error using Ktor“未找到转换:类 io.ktor.utils.io.ByteChannelNative”错误使用 Ktor
【发布时间】:2021-03-14 05:41:50
【问题描述】:

我正在尝试获取和反序列化托管在 github 上的一些数据。

{
  "Meals": [
    {
      "id": "1598044e-5259-11e9-8647-d663bd870b02",
      "name": "Tomato pasta",
      "quantity": [{
        "quantity": 1 },
        {
          "quantity": 2
        },
        {
          "quantity": 3
        }],
      "availableFromDate": "1605802429",
      "expiryDate": "1905802429",
      "info": "Vegetarian",
      "hot": false,
      "locationLat": 57.508865,
      "locationLong": -6.292,
      "distance": null
    },
    {
      "id": "2be2d854-a067-43ec-a488-2e69f0f2a624",
      "name": "Pizza",
      "quantity": [{
        "quantity": 1 },
        {
        "quantity": 2
        },
        {
          "quantity": 3
        }
      ],
      "availableFromDate": "1605802429",
      "expiryDate": "1905902429",
      "info": "Meat",
      "hot": false,
      "locationLat": 51.509465,
      "locationLong": -0.135392,
      "distance": null
    }
  ]
}

如果我在本地启动 json-server,那么它可以完美运行,所以我知道我的数据类不是问题所在。但是,当我尝试从该 github 链接执行相同操作时,出现此错误:

Error Domain=KotlinException Code=0 "No transformation found: class io.ktor.utils.io.ByteChannelNative -> class kotlin.collections.List

我感觉这可能与设置 ContentType 或类似的东西有关,但到目前为止我还没有成功指定。

这是我提出请求的代码:

class MealApi {

    private val httpClient = HttpClient {
        install(JsonFeature) {
            val json = Json { ignoreUnknownKeys = true }
            serializer = KotlinxSerializer(json)
        }
    }

    suspend fun getAllMeals(): List<Meal> {
        return httpClient.get(endpoint)
    }
}

为了完整起见,这是我的数据类:

@Serializable
data class Meal(
    @SerialName("id")
    val id: String,
    @SerialName("name")
    val name: String,
    @SerialName("quantity")
    val quantity: List<Quantity>,
    @SerialName("availableFromDate")
    var availableFromDate: String,
    @SerialName("expiryDate")
    var expiryDate: String,
    @SerialName("info")
    val info: String,
    @SerialName("hot")
    val hot: Boolean,
    @SerialName("locationLat")
    val locationLat: Float,
    @SerialName("locationLong")
    val locationLong: Float,
    @SerialName("distance")
    var distance: Double? = null
)

@Serializable
data class Quantity(
    @SerialName("quantity")
    val quantity: Int
)

更新

我发现此服务器 https://gitcdn.link/ 允许您使用正确的 Content-Type 提供原始 github 文件。

【问题讨论】:

    标签: json kotlin ktor kotlin-multiplatform


    【解决方案1】:

    我已经搜索了很多如何更改服务器响应标头(将 plain/text 更改为 application/json),但似乎 ktor 实际上不允许这样做:

    一个不错的方法应该是允许ResponseObserver 更改服务器响应标头并通过修改响应。但实际上你不能。

    正如您所指出的,您的问题取决于原始 github 页面提供标头 Content-Type=plain/text 而不是 ContentType=application/json 的事实。

    因此,当您在真实服务器中运行 API 时,IRL 不会发生,因为您会注意在服务器级别放置正确的内容类型。

    但如果您想要解决此问题,您可以用这种方式重写您的 api 调用:

    suspend fun getAllMealsWithFallback() {
        var meals: Meals? = null
        try {
            meals = httpClient.get(endpoint)
        } catch (e: NoTransformationFoundException) {
            val mealsString: String = httpClient.get(endpoint)
            val json = kotlinx.serialization.json.Json {
                ignoreUnknownKeys = true
            }
            meals = json.decodeFromString(mealsString)
        } finally {
            println("Meals: ${meals?.meals}")
        }
    }
    

    我必须添加这个类以符合您在 github 链接中提供的 json 文本。

    @Serializable
    data class Meals(
        @SerialName("Meals")
        val meals: List<Meal>,
    )
    

    【讨论】:

    • 我也在 get.xml 中添加了 contentType。让我知道它是否有效。我现在无法自己尝试。我打算尽快尝试一下。
    • 完美。感谢您不遗余力地帮助我,我真的很感激!
    【解决方案2】:

    如果问题是 Content-Type:

    您可以通过将JsonFeature 块扩展为:

    install(JsonFeature) {
        val json = Json { ignoreUnknownKeys = true }
        serializer = KotlinxSerializer(json)
        receiveContentTypeMatchers += object : ContentTypeMatcher {
            override fun contains(contentType: ContentType): Boolean =
                contentType == ContentType("text", "plain")
        }
    }
    

    【讨论】:

      【解决方案3】:

      试试这个:

      install(JsonFeature) {
          serializer = KotlinxSerializer(KotlinJson { ignoreUnknownKeys = true })
          acceptContentTypes = acceptContentTypes + ContentType.Any
      }
      

      如果您想接受所有内容类型。或者如果您愿意,请使用ContentType.Text.AnyContentType.Text.Html

      【讨论】:

        猜你喜欢
        • 2020-10-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-25
        • 2022-01-09
        • 2013-09-04
        • 2019-04-29
        • 2018-05-19
        相关资源
        最近更新 更多