使用Java创建代理服务器导致二进制文件损坏
解决Spark Java代理服务器二进制文件损坏问题
嘿,我来帮你搞定这个二进制文件(比如字体)损坏的问题!
问题根源
你遇到的核心问题应该是用字符流处理了二进制响应体。当你把Apache HttpClient返回的响应内容转换成字符串(比如用EntityUtils.toString())再返回给客户端时,二进制数据会被错误地按字符编码解析,导致原始字节丢失或篡改——毕竟字符流是为文本设计的,根本不适合处理图片、字体、压缩包这类二进制文件。
解决方案:改用字节流处理响应体
你需要修改响应内容的处理逻辑,直接用字节流把Apache HttpClient的响应体复制到Spark的输出流里,完全跳过字符编码的步骤。同时要确保正确转发所有和二进制内容相关的响应头(比如Content-Type、Content-Length)。
完整代码示例
先保留你现有的mapStatus方法,然后添加处理响应体和响应头的逻辑:
private static void mapStatus(HttpResponse response, spark.Response res) { res.status(response.getStatusLine().getStatusCode()); } private static void mapHeadersAndBinaryBody(HttpResponse response, spark.Response res) { // 1. 转发所有响应头 Header[] headers = response.getAllHeaders(); for (Header header : headers) { res.header(header.getName(), header.getValue()); } // 2. 处理二进制响应体 HttpEntity entity = response.getEntity(); if (entity != null) { try (InputStream inputStream = entity.getContent(); OutputStream outputStream = res.raw().getOutputStream()) { // 用缓冲区字节流复制数据,避免内存溢出 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush(); } catch (IOException e) { // 处理异常,返回500错误 res.status(500); res.body("Failed to forward binary content"); } } }
然后在你的代理路由里调用这两个方法:
post("/proxy/*", (req, res) -> { // 1. 用Apache HttpClient发送请求到目标服务器,获取response HttpResponse targetResponse = sendRequestToTargetServer(req); // 2. 同步状态码 mapStatus(targetResponse, res); // 3. 同步响应头和二进制响应体 mapHeadersAndBinaryBody(targetResponse, res); // Spark不需要返回内容,因为已经直接写入输出流了 return null; });
关键注意事项
- 绝对不要用
EntityUtils.toString()处理二进制实体,这个方法会强制把字节转成字符串,直接破坏二进制数据。 - 转发所有响应头很重要,比如
Content-Type会告诉客户端这是字体文件还是图片,Content-Encoding如果是gzip的话也需要保留,否则客户端无法正确解压。 - 使用缓冲区字节流复制数据,避免一次性把大文件加载到内存里,防止OOM。
内容的提问来源于stack exchange,提问作者abhinav pandey
相关产品推荐
相关产品推荐

