在Sql server中压缩字符串并在javascript中解压缩

4
我想将数据库中的长字符串传输到网页上。因此,我希望尝试在服务器端压缩字符串,在客户端解压缩字符串的方法。
目前,我的 SQL Server 代码如下:
select compress('this is just a sample string')

它返回以下内容:

0x1F8B08000000000004002BC9C82C5600A2ACD2E212854485E2C4DC829C5485E292A2CCBC7400206D53921C000000

现在我需要一个 JavaScript 函数来撤销压缩操作:
var str = "0x1F8B08000000000004002BC9C82C5600A2ACD2E212854485E2C4DC829C5485E292A2CCBC7400206D53921C000000";
alert(decompressed(str));

应该弹出警报 "这只是一个示例字符串"。


1
在SQL服务器中,compress()函数返回一个GZIP压缩的字节数组,因此您需要查找或编写相应的代码来进行解压缩。JavaScript中没有内置类似的功能,给出库或其他外部资源的建议被视为不适合在SO上讨论的话题。 - Karl-Johan Sjögren
1
在MSSQL中将压缩文本存储在varbinary列中是可以的。请参见此处:SQL Server 2016中的压缩和解压缩函数。但是:您是否尝试启用动态压缩并从服务器提供gzipped文本内容?传输的gzipped文本将在客户端浏览器上透明处理,无需自定义JavaScript解压缩循环的开销。 - deblocker
4个回答

6
首先,让我解释一下 VARBINARY(MAX) 在 SSMS 中的存储和显示方式之间的区别。
字符串“0x1F8B0800000000000...”是由 SSMS 创建的 varbinary 数据的十六进制表示形式,该二进制值大多是不可打印字符。因此,如果您尝试在 Java 代码中使用此字符串,则无法直接使用。
我在这里创建了一个示例,如果您按下“STEP”按钮,您将看到实际值:HexToBin
这就是为什么您的第二个示例不起作用,您需要从数据库中读取字节数组,然后在 zlib 中使用该字节数组。
以下是如何在 Java 中使用 deflate 的很好的示例:Java Decompress a string compressed with zlib deflate

3
也许你想要这样的东西: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期望输入是数字数组。然后decompressed函数使用zlib来解压缩该数组。zlib的decompress函数返回一个数字数组,所以我们将它再次转换为字符串。


3
当您运行此查询:select compress('this is just a sample string')(例如使用MSSQL Server Management Studio),您将看到二进制压缩文本的十六进制格式的文本表示形式。
我用被转换为varcharnvarcharlorem ipsum长文本进行了测试(您可能会注意到该文本内部没有双字节字符,但对于这个示例没有关系):
这个压缩后的长文本存储在MSSQL的一个varbinary(max)列中:
--------VARCHAR----------    --------NVARCHAR--------
Original     Hex   Binary    Original    Hex   Binary
   13046    4024     2011       13046   4748     2373
所以,在这里最好的选择是传输二进制数据,而不是十六进制表示形式。

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

服务器端: 这里有一个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的工作示例:

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的工作片段:

致谢: 此处用于解压缩的库gunzip.min.js来自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);

如果您查看响应字节长度,以13046字节的示例文本为例,您将会发现只有2015字节实际上在网络上传输。


2
如@Karl-Johan Sjögren所述,sql函数compress()返回一个GZIP值,在JavaScript中您将无法解压缩它,除非使用外部库,如zlib。请注意保留HTML标签。

我可以使用外部库。 - Behnam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接