一、概念二、添加依赖最新版本[versions] ktor 3.6.0 [libraries] ktor-core { module io.ktor:ktor-client-core, version.ref ktor } #核心库 ktor-okhttp { module io.ktor:ktor-client-okhttp, version.ref ktor } #Android用OkHttp ktor-negotiation { module io.ktor:ktor-client-content-negotiation, version.ref ktor } #内容协商 ktor-serialization { module io.ktor:ktor-serialization-kotlinx-json, version.ref ktor } #序列化 ktor-logging { module io.ktor:ktor-client-logging, version.ref ktor } #日志三、客户端迁移直接复用 OkHttp 设置只需要将 Retrofit 配置的替换掉。object KtorClient { // Json解析 private val json by lazy { Json { prettyPrint true // isLenient true //宽松解析单引号、松散JSON ignoreUnknownKeys true // 忽略接口返回的多余字段服务端新增字段不会导致崩溃容错升级 } } // OkHttp private val okHttp by lazy { OkHttpClient.Builder().build() } // Ktor private val ktor by lazy { HttpClient(OkHttp) { // 内容协商 install(ContentNegotiation) { json(json) // Json解析 } // BaseUrl install(DefaultRequest) { url() } // 引擎 engine { preconfigured okHttp // 用okhttp } } } // ApiService val apiService by lazy { ApiService(ktor) } }四、网络请求迁移从「声明式注解」变成「显式函数调用」。RetrofitKtorGET / POST / PUT / DELETEclient.get() / client.post() / client.put() / client.delete()PathURL 字符串拼接users/$idQueryparameter(key, value)QueryMapparameter()逐个调用或遍历 MapBodysetBody(obj)Headerheader(name, value)Headersheader()多次调用FormUrlEncodedFieldsetBody(FormDataContent(...))或submitForm()MultipartPartsetBody(MultiPartFormDataContent(...))Url直接传完整 URLStreamingprepareGet().execute { }流式读取class ApiService( private val client: HttpClient ) { // 请求方法 }4.1 GET// Retrofit GET(users) suspend fun getUsers(): ListUser // Ktor suspend fun getUsers(): ListUser client.get(users).body()4.2 Path 参数// Retrofit GET(search) suspend fun search( Query(keyword) keyword: String, Query(page) page: Int ): ListResult // Ktor suspend fun search(keyword: String, page: Int): ListResult client.get(search) { parameter(keyword, keyword) parameter(page, page) }.body()4.3 Query 参数// Retrofit GET(search) suspend fun search( Query(keyword) keyword: String, Query(page) page: Int ): ListResult // Ktor suspend fun search(keyword: String, page: Int): ListResult client.get(search) { parameter(keyword, keyword) parameter(page, page) }.body()4.4 POST Body// Retrofit POST(users) suspend fun createUser(Body user: User): User // Ktor suspend fun createUser(user: User): User client.post(users) { contentType(ContentType.Application.Json) setBody(user) }.body()4.5 Header// Retrofit GET(profile) suspend fun getProfile(Header(Authorization) token: String): Profile // Ktor suspend fun getProfile(token: String): Profile client.get(profile) { header(Authorization, token) }.body()4.6 固定 HeaderHeaders// Retrofit Headers(X-Client: android, Accept: application/json) GET(config) suspend fun getConfig(): Config // Ktor suspend fun getConfig(): Config client.get(config) { header(X-Client, android) header(Accept, application/json) }.body()4.7 表单提交FormUrlEncoded// Retrofit FormUrlEncoded POST(login) suspend fun login( Field(username) username: String, Field(password) password: String ): LoginResult // Ktor import io.ktor.client.request.forms.* suspend fun login(username: String, password: String): LoginResult client.submitForm( url login, formParameters parameters { append(username, username) append(password, password) } ).body() // 或者用 setBody suspend fun login(username: String, password: String): LoginResult client.post(login) { setBody(FormDataContent(parameters { append(username, username) append(password, password) })) }.body()4.8 文件上传Multipart// Retrofit Multipart POST(upload) suspend fun upload( Part file: MultipartBody.Part, Part(desc) desc: RequestBody ): UploadResult // Ktor import io.ktor.client.request.forms.* import io.ktor.http.content.* suspend fun upload(fileBytes: ByteArray, fileName: String, desc: String): UploadResult client.post(upload) { setBody(MultiPartFormDataContent( formData { append(desc, desc) append(file, fileBytes, Headers.build { append(HttpHeaders.ContentType, image/jpeg) append(HttpHeaders.ContentDisposition, filename\$fileName\) }) } )) }.body()4.9 完整 URLUrl// Retrofit GET suspend fun getByUrl(Url url: String): Response // Ktor suspend fun getByUrl(url: String): Response client.get(url).body()五、返回值基类
企业数字化 ERP 产品动态
相关推荐
某广告推广平台 API 签名算法逆向分析还原 阅读须知
本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!擅自使用… · 2026/9/26 4:08:51
React 列表与表单 React 列表与表单 前置:React State 与事件 目标:map key 渲染列表;表单提交增加待办。 动手
完整代码:react2/04-lists-forms/demo
cd react2/04-lists-forms/demo
npm install
npm run dev要点
{todos.map((todo) > (<… · 2026/9/26 4:08:51
Vue.js渐进式框架实战:从入门到工程化与面试考点全解析 做过几年前端之后回看,我对Vue.js最服气的一点,恰恰是“渐进式框架”这个定位。它不是那种逼你全量拥抱的“全家桶式”框架,而是允许你从一个页面、一个按钮、一个组件开始,一点一点把整个前端工程带起来。这个设计哲学࿰… · 2026/9/26 4:45:39
分布式电源接入配电网潮流计算程序定制全解析 我最早接触“分布式电源接入配电网潮流计算”这个需求,是因为一条10kV馈线末端接入几个兆瓦的光伏电站后,用传统的手算简化公式校核电压偏差,结果和实测数据差了将近两个百分点。从那之后我就明白,分布式电源接入后的配电网&#… · 2026/9/26 4:45:39
Windows 10 1803安全基线实战:策略导入、参数设置与故障避坑 简介:针对Windows 10 1803版本的安全基线配置与核查工具包,适用对象为系统管理员、安全运维人员及合规审计人员,可用于政企桌面终端安全管控与等保合规建设,帮助快速落地企业级安全基线标准。压缩包为zip格式,共72个文… · 2026/9/26 4:45:33
知识竞赛系统开发实战:从题型建模到WebSocket实时同步 简介:知识竞赛系统是一套基于C/MFC开发的可运行在线答题平台,面向高校学生、竞赛组织者及需要快速搭建答题场景的开发者,覆盖试题维护、参赛者管理、限时答题和自动排名等核心需求。压缩包共61个文件,约7.68MB,文件类型… · 2026/9/26 4:45:33
CSS英文换行终极指南:word-break与overflow-wrap实战解析 做前端的,谁没被一行超长英文爆过框?一个URL、一串订单号、一段没有空格的base64,直接像根棍子一样把卡片、按钮、flex布局顶穿,页面瞬间稀碎。更气人的是,网上搜了一圈,答案就俩词:word-break、… · 2026/9/26 4:45:33
基于Node.js+PHP+Vue的社区捐赠管理系统全栈开发实战 之前帮好几个朋友看过类似的“全栈毕设项目”,这是地方社区最常见的场景:居民有闲置物品愿意捐出来,社区需要一套系统登记、展示、发放,操作的人又多半不是技术人员。所以我从一开始就确定了这个技术组合:nodejs php … · 2026/9/26 4:45:33
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46