【问题标题】:Compress string in Sql server and decompress in javascript在Sql server中压缩字符串并在javascript中解压
【发布时间】:2020-03-22 08:50:54
【问题描述】:

我想将一个长字符串从我的数据库传输到我的网页。 所以,我想尝试在我的服务器中压缩我的字符串并在客户端解压缩它的方法。

到目前为止,我的 sql server 代码中有这个:

select compress('this is just a sample string')

返回这个:

0x1F8B08000000000004002BC9C82C5600A2ACD2E212854485E2C4DC829C5485E292A2CCBC7400206D53921C000000

现在我的 javascript 中需要一个函数来恢复压缩操作:

var str = "0x1F8B08000000000004002BC9C82C5600A2ACD2E212854485E2C4DC829C5485E292A2CCBC7400206D53921C000000";
alert(decompressed(str));

应该提醒“这只是一个示例字符串”。

【问题讨论】:

  • compress() 在 SQL 服务器中返回一个 GZIP 压缩字节数组,因此您必须寻找或编写一些东西来解压缩它。 javascript 中没有内置任何类似的东西,并且为库或其他场外资源提供建议在 SO 上被认为是题外话。
  • 在 MSSQL 的 varbinary 列中存储压缩文本是可以的。见这里:Compression and decompression functions in SQL Server 2016。但是:您是否尝试过启用动态压缩并从您的服务器提供 gzip 压缩的文本内容?传输的 gzip 压缩文本将在客户端从浏览器透明地处理,没有自定义 JavaScript 解压缩循环的开销。

标签: javascript sql-server compression


【解决方案1】:

首先,让我解释一下 VARBINARY(MAX) 在 SSMS 中的存储和显示方式之间的区别。
字符串“0x1F8B0800000000000...”是数据库中存储的 varbinary 数据的 SSMS 创建的十六进制表示。底层二进制值主要是不可打印的字符。所以如果你尝试在你的java代码中使用这个字符串,它就不能直接工作。

我在这里创建了一个例子,如果你按下“STEP”按钮,你会看到真正的价值: HexToBin

这就是为什么你的第二个例子不起作用,你需要从数据库中读取字节数组,然后在 zlib 中使用这个字节数组。

有一个很好的例子如何在java中使用deflate: Java Decompress a string compressed with zlib deflate

【讨论】:

    【解决方案2】:

    也许你想要这样的东西:https://jsfiddle.net/58mgsy9a/

    const parseString = str => {
        const strWithoutprefix = str.slice(2);
        const array = strWithoutprefix.match(/.{1,2}/g);
        return array.map(pair => parseInt(pair, 16));
    };
    
    const decompressed = gzipArray => {
        const gunzip = new Zlib.Gunzip(gzipArray);
        const plain = gunzip.decompress();
        return String.fromCharCode(...plain);
    };
    
    var str = "0x1F8B08000000000004002BC9C82C5600A2ACD2E212854485E2C4DC829C5485E292A2CCBC7400206D53921C000000";
    alert(decompressed(parseString(str)));
    

    parseString 函数接受您的输入字符串并将其转换为一个数字数组,因为 zlib 需要一个数字数组作为输入。然后解压函数使用zlib解压数组。 zlib的解压函数返回一个数字数组,所以我们把它转回字符串。

    【讨论】:

      【解决方案3】:

      当您运行此查询时:select compress('this is just a sample string')(例如使用 MSSQL Server Management Studio)您将看到 二进制文件的 十六进制 格式的 text 表示 压缩文本。

      我对 lorem ipsum 长文本进行了测试,该长文本也被转换为 varcharnvarchar(您可能会注意到该文本中没有双字节字符,但它这个例子没关系):

      这个压缩的长文本存储在 MSSQL 的 varbinary(max) 列中:

      --------VARCHAR------------ --------NVARCHAR-------- 原始十六进制二进制原始十六进制二进制 13046 4024 2011 13046 4748 2373

      所以,这里最好的选择是从后端传输二进制数据,不是十六进制表示。

      告诉浏览器响应已被压缩:

      服务器端:这是 PHP 中的示例端点:

      <?php  /* getcompressed.php */
          header("Content-Encoding: gzip");
          header("Vary: Accept-Encoding");
          header("Content-type: text/html; charset=UTF-16"); /* nvarchar */
          $serverName = 'testserver';
          $connectionOptions = array('Database'=>'testdatabase');
          $conn = sqlsrv_connect($serverName, $connectionOptions);  
          $sql = 'SELECT compressed FROM tb_compression WHERE id = 1';
          $qry = sqlsrv_query($conn, $sql);
          $row = sqlsrv_fetch_array($qry);
          $compressed = $row[0];
          sqlsrv_close($conn);
          echo $compressed;
      ?>
      

      客户端:这是一个在 JavaScript 中工作的 sn-p:

      var request = new XMLHttpRequest();
      request.onload = function(e) {
          var text = e.currentTarget.responseText;
          console.log(text); /* Here You go */
      };
      request.responseType = 'text';
      request.open('GET', 'getcompressed.php', true);
      request.send(null);
      

      这在 Chrome 和 FF 中也适用于我。试试看。

      使用 gunzip javaScript 库:

      服务器端:这是 PHP 中的示例端点:

      <?php  /* getcompressed.php */
          header('Content-Type: application/octet-stream');
          $serverName = 'testserver';
          $connectionOptions = array('Database'=>'testdatabase');
          $conn = sqlsrv_connect($serverName, $connectionOptions);  
          $sql = 'SELECT compressed FROM tb_compression WHERE id = 1';
          $qry = sqlsrv_query($conn, $sql);
          $row = sqlsrv_fetch_array($qry);
          $compressed = $row[0];
          sqlsrv_close($conn);
          echo $compressed;
      ?>
      

      客户端:这是一个在 JavaScript 中工作的 sn-p:

      CREDIT:这里用于解压的库是gunzip.min.js from Imaya Yuta

      var request = new XMLHttpRequest();
      request.onload = function(e) {
          var response = new Uint8Array(e.currentTarget.response);
          console.log(response.byteLength);
          /* Strip out the response termination */
          var compressed = response.subarray(0, response.byteLength - 4);
          var gunzip = new Zlib.Gunzip(compressed);
          var decompressed = gunzip.decompress();
          var encoding = 'utf-8'; /* For varchar text (ansi) */
          //var encoding = 'utf-16'; /* For nvarchar text (double-byte) */
          var text = new TextDecoder(encoding).decode(decompressed);
          console.log(text); /* Here You go */
      };
      request.responseType = 'arraybuffer';
      request.open('GET', 'getcompressed.php', true);
      request.send(null);
      

      如果您查看 response.byteLength,例如 13046 字节的文本,您将检查是否只有 2015 字节有效地通过网络传输。

      【讨论】:

        【解决方案4】:

        正如@Karl-Johan Sjögren 所说,sql 函数 compress() 返回一个 GZIP 值,如果不使用 zlib 等外部库,您将无法在 javascript 上解压缩它。

        【讨论】:

        • 我可以使用外部库。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多