You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 11 HttpClient转OkHttp实现POST获取PDF是否正确?

问题:OkHttp实现POST请求获取PDF后展示报错

需求:通过POST请求获取PDF文件并展示给用户

尝试过程:

  • 已有基于Java 11 HttpClient API的示例代码,可向labelary发送POST请求将ZPL字符串转换为PDF文件:
var zpl = "^xa^cfa,50^fo100,100^fdHello World^fs^xz";

// 调整打印密度(8dpmm)、标签宽度(4英寸)、标签高度(6英寸)和标签索引(0)
var uri = URI.create("http://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/");
var request = HttpRequest.newBuilder(uri)
    .header("Accept", "application/pdf") // 注释此行可获取PNG图片
    .POST(BodyPublishers.ofString(zpl))
    .build();
var client = HttpClient.newHttpClient();
var response = client.send(request, BodyHandlers.ofByteArray());
var body = response.body();

if (response.statusCode() == 200) {
    var file = new File("label.pdf"); // 获取PNG时修改文件名
    Files.write(file.toPath(), body);
} else {
    var errorMessage = new String(body, StandardCharsets.UTF_8);
    System.out.println(errorMessage);
}
  • 由于该代码无法在Android中运行,改用Squareup OkHttp库实现:
fun fetch(completion: (InputStream?) -> Unit) {
    val url = "https://api.labelary.com/v1/printers/8dpmm/labels/4x6/0/"
    val postBody = "^xa^cfa,50^fo100,100^fdHello World^fs^xz"
    val text = MediaType.parse("text/plain;charset=utf-8")
    val body = RequestBody.create(text, postBody)
    val labelFetch = OkHttpClient()
    val request = Request.Builder()
        .header("Accept", "application/pdf")
        .url(url)
        .post(body)
        .build()

    labelFetch.newCall(request).enqueue(object : Callback {
        override fun onFailure(request: Request?, e: IOException?) {

        }

        override fun onResponse(response: Response?) {
            val pdfData = response?.body()?.byteStream()
            completion(pdfData)
        }
    })
}

问题:获取到InputStream后用pdfViewer展示时,出现错误:

java.io.IOException: file not in PDF format or corrupted

请问上述OkHttp的转换实现是否正确?


分析与解决

你的OkHttp实现存在几个潜在问题,是导致PDF格式错误的主要原因:

  1. 未校验响应状态
    代码里没有检查响应是否成功,如果接口返回非200状态码(比如400参数错误、500服务异常),返回的是错误文本而非PDF流,直接传给pdfViewer必然报格式错误。必须先判断响应状态,失败时读取错误信息排查问题:

    override fun onResponse(response: Response?) {
        if (response?.isSuccessful == true) {
            val pdfData = response.body()?.byteStream()
            completion(pdfData)
        } else {
            val errorMsg = response?.body()?.string()
            // 打印错误信息,排查接口返回的具体问题
            completion(null)
        }
    }
    
  2. 缺少Content-Type请求头
    Java版本的代码虽然没显式设置Content-Type,但BodyPublishers.ofString()会默认带上合适的文本类型头,而OkHttp的实现仅声明了RequestBody的MediaType,未在请求头中明确传递。部分接口对这个头的校验严格,需手动添加:

    val request = Request.Builder()
        .header("Accept", "application/pdf")
        .header("Content-Type", "text/plain;charset=utf-8") // 新增此行
        .url(url)
        .post(body)
        .build()
    
  3. InputStream处理不规范
    OkHttp的ResponseBody.byteStream()是一次性资源,且需确保完整读取。如果直接传递给pdfViewer时出现线程问题或读取不完整,会导致数据截断。建议先将流转换为字节数组或临时文件,再传给阅读器:

    override fun onResponse(response: Response?) {
        if (response?.isSuccessful == true) {
            response.body()?.let { body ->
                val byteArray = body.bytes()
                // 转为临时文件(避免流失效问题)
                val tempFile = File(context.cacheDir, "temp_label.pdf")
                FileOutputStream(tempFile).use { it.write(byteArray) }
                completion(tempFile.inputStream())
            } ?: completion(null)
        } else {
            completion(null)
        }
    }
    
  4. HTTP/HTTPS差异
    Java版本用的是http://协议,OkHttp版本改用了https://,部分环境下HTTPS证书校验问题可能导致响应异常。可以先换回HTTP测试,确认是否是协议差异导致的问题。

按上述步骤调整后,就能解决PDF格式错误的问题。

内容的提问来源于stack exchange,提问作者F.Mysir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 22:31:15