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

Node.js压缩字符串后无法在Swift iOS中解压的问题求助

问题分析

你的跨平台压缩解压失败主要有以下几个核心原因:

  1. Base64解码逻辑错误:Swift解压时错误地将Base64字符串按UTF-8编码转换为Data,而非解码Base64得到原始压缩二进制数据。
  2. 不必要的字节截断:解压时错误跳过前2字节,破坏了zlib格式的头部校验信息。
  3. 缓冲区内存管理问题:压缩时使用NSData(bytesNoCopy:)导致内存管理不匹配,可能生成错误的压缩数据。
  4. 算法匹配疏漏:未严格对齐Node.js与Swift的压缩格式标准。

修正后的解决方案

1. Node.js端代码(保持原样,确认格式)

你的Node.js代码是正确的,zlib.deflate默认生成带zlib头和校验和的标准格式压缩数据,转Base64后可直接传输:

var input = "Bytes stored within a computer do not have a bit order";
var zlib = require('zlib');
compress(input)

function compress(input){
     zlib.deflate(input, (err, buffer) =>{
         if (!err){
             console.log(buffer.toString('base64'));
         }
    });
}

运行后会输出对应的Base64字符串(示例:eJzLSM3JyVcozy/KSVEEAB0JBFQ==,实际值以你的运行结果为准)。

2. Swift端正确的解压代码

核心步骤:

  • 解码Base64为压缩二进制数据
  • 使用COMPRESSION_ZLIB算法解压
  • 将解压后的Data转换为UTF-8字符串

完整代码:

import Foundation

// 替换为Node.js实际输出的Base64压缩字符串
let nodejsCompressedBase64 = "eJzLSM3JyVcozy/KSVEEAB0JBFQ=="

// 解压函数
func decompressZlibData(_ compressedData: Data) -> String? {
    let maxOutputSize = 8_000_000 // 根据业务场景调整缓冲区大小
    guard let outputBuffer = malloc(maxOutputSize) else {
        print("内存分配失败")
        return nil
    }
    defer { free(outputBuffer) } // 确保内存释放
    
    let decompressedSize = compressedData.withUnsafeBytes { srcBytes in
        compression_decode_buffer(
            outputBuffer.bindMemory(to: UInt8.self, capacity: maxOutputSize),
            maxOutputSize,
            srcBytes.baseAddress?.bindMemory(to: UInt8.self, capacity: compressedData.count),
            compressedData.count,
            nil,
            COMPRESSION_ZLIB
        )
    }
    
    guard decompressedSize > 0 else {
        print("解压失败")
        return nil
    }
    
    let decompressedData = Data(bytes: outputBuffer, count: decompressedSize)
    return String(data: decompressedData, encoding: .utf8)
}

// 执行解压流程
if let compressedData = Data(base64Encoded: nodejsCompressedBase64),
   let decompressedString = decompressZlibData(compressedData) {
    print("解压结果:\(decompressedString)")
} else {
    print("Base64解码或解压失败")
}

3. Swift端正确的压缩代码(用于跨平台验证)

如果需要在Swift端压缩后和Node.js结果匹配,使用以下代码(确保算法与参数对齐):

import Foundation

func compressStringToZlibBase64(_ input: String) -> String? {
    guard let inputData = input.data(using: .utf8) else {
        print("字符串转Data失败")
        return nil
    }
    
    let maxOutputSize = inputData.count // 压缩后大小不会超过原数据(极端情况可适当放大)
    guard let outputBuffer = malloc(maxOutputSize) else {
        print("内存分配失败")
        return nil
    }
    defer { free(outputBuffer) }
    
    let compressedSize = inputData.withUnsafeBytes { srcBytes in
        compression_encode_buffer(
            outputBuffer.bindMemory(to: UInt8.self, capacity: maxOutputSize),
            maxOutputSize,
            srcBytes.baseAddress?.bindMemory(to: UInt8.self, capacity: inputData.count),
            inputData.count,
            nil,
            COMPRESSION_ZLIB
        )
    }
    
    guard compressedSize > 0 else {
        print("压缩失败")
        return nil
    }
    
    let compressedData = Data(bytes: outputBuffer, count: compressedSize)
    return compressedData.base64EncodedString()
}

// 测试压缩
let testString = "Bytes stored within a computer do not have a bit order"
if let compressedBase64 = compressStringToZlibBase64(testString) {
    print("Swift压缩后的Base64:\(compressedBase64)")
    // 此时应与Node.js输出的Base64一致(或因压缩级别细微差异略有不同,但解压后结果完全一致)
}

关键注意事项

  • Base64处理:必须使用Data(base64Encoded:)解码Base64字符串,绝对不能用data(using: .utf8)。
  • 算法对齐:Node.js的zlib.deflate对应Swift的COMPRESSION_ZLIB;如果Node.js使用zlib.deflateRaw(原始deflate格式,无头部校验),则Swift需切换为COMPRESSION_DEFLATE。
  • 内存管理:使用malloc/free或Swift的UnsafeMutablePointer时,必须通过defer确保内存释放,避免泄漏。
  • 缓冲区大小:解压时需分配足够大的缓冲区,可根据原始数据的预估体积灵活调整。

内容的提问来源于stack exchange,提问作者Hugo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:24:18