HTTP POST multipart/form-dataでファイルを送信してみる
前回、RetrofitでJSON over HTTPで送受信をしてみましたが、今回はHTTP POST multipart/form-dataでファイルを送信してみます。
Serviceのインタフェース
ミソは@Post、@Multipartアノテーションをメソッドに付けます。
引数の送信するファイルは@Partアノテーションを付けます。引数の型はokhttp3.MultipartBody.Partになります。
interface MediCodeSendService {
・・・
@POST
@Multipart
suspend fun doUpload(
@Url url: String,
@Part part: MultipartBody.Part
): Response<Unit>
}
戻り値の型ですが、ファイルをアップロードする場合でHTTPのレスポンスBodyがない場合、Responseの型引数はUnitとなります。ファイルをアップロードは成功したか、失敗したかなのでHTTP Statusで足りるのでレスポンスBodyが何も返らない場合があります。
Retrofitの公式ではあまりこの辺は詳しくかかれていませんが(そもそもドキュメントが貧弱)、Retrofitの公式ページの FORM ENCODED AND MULTIPARTに書かれています。
Repositoryクラス
Repositoryクラスの初期化の部分は前回と同じです。ファイルアップロードのメソッドだけ追加します
class SampleRepository(baseUrl: String, timeout: Long) {
/** サービス */
private var service: SampleService
init {
// ロギング
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BASIC)
val client = OkHttpClient.Builder()
.readTimeout(timeout, TimeUnit.SECONDS)
.connectTimeout(timeout, TimeUnit.SECONDS)
.addInterceptor(logging)
.build()
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
service = Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create(SampleService::class.java)
}
・・・
suspend fun doUplaod(uploadUrl: String, datFile: File): Pair<String, String> {
val part = MultipartBody.Part.createFormData(
"data", "testData.csv", datFile.asRequestBody("text/csv".toMediaType())
)
val response = service.doUpload(uploadUrl, part)
}
}
Repositoryクラスの中でFileからMultipart/form-dataに相当する、MultipartBody.Partのインスタンスを作ってやらないといけません。
val part = MultipartBody.Part.createFormData(
"data", "testData.csv", datFile.asRequestBody("text/csv".toMediaType())
の部分がそれに相当しますが、ここはOkHttp3の機能なのでRetrofitの公式ページには触れられていません。
MultipartBody.Part.createFormDataの
- 第一引数が、Content-Dispositionのname属性
- 第二引数が、Content-Dispositionのfilename属性
- 第三引数が、ファイルの実体、asRequestBody(・・・)が、Content-Type: text/csvに相当
となります。
Content-Disposition: form-data; name="data"; filename="testData.csv"
Content-Type: text/csv
HTTP Heaerを付けてみる
HTTP request headerを付けて送る方法はRetrofitの公式ページの HEADER MANIPULATIONに書かれています。
HTTP headerを1個だけ、固定で送信する場合
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
HTTP headerを複数、固定で送信する場合
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
HTTP headerを1個だけ、引数に含めて可変で送信する場合
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
HTTP headerを複数、引数に含めて可変で送信する場合
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
response headerは戻り値のResponseから取得します。
val response = service.doUpload(uploadUrl, part)
response.headers().forEach {header ->
println("${header.first} = ${header.second}") // 全部
}
val hogeHeader = response.headers()["X-HOGE-HEADER"] ?: "" // 1個だけ狙い撃ち