我在解压缩以前压缩的字节流时遇到了问题。基本上,我正在尝试使用函数bytes.NewReader()
创建一个读取器,然后使用gzip.NewReader()
函数解压缩流。最后,我想以字符串或字节格式返回实际值。
我知道gzip.NewReader
需要io.Reader
作为输入,但是,据我所知,键入Reader
实现了接口io.Reader
。我认为这应该不会导致任何错误,但我想知道在这种情况下可能有什么问题。如果您能帮我解决这个问题,我将不胜感激!
如果你想知道这段文字是什么,
"amZzRUR2NHVtcVpiZHNROHJiTTNYeGdUSndGTlVDZC9jaElSK1lXcFlJOD0="
这是从我的客户端 Python 脚本发送的示例输入。它使用 gzip 进行压缩,使用 AES128 进行加密,最后按此顺序以 base64 进行编码。
客户端代码:
import time
import json
import requests
import random
import gzip
import base64
from Crypto.Cipher import AES
baseurl = 'http://0.0.0.0:80'
key = 'TfvY7I358yospfWKcoviZizOShpm5hyH'
iv = 'mb13KcoviZizvYhp'
MODE = AES.MODE_CFB
BLOCK_SIZE = 16
SEGMENT_SIZE = 128
def http_post(url, data):
print('Going to make a request to {} with the following data: {}'.format(url, data))
r = requests.post(url,
data=data,
headers={'Content-type': 'application/json; charset=utf-8',
'Connection': 'keep-alive'}, )
if r.status_code != 200:
print('Server returned unexpected response code {}, and content: {}'.format(r.status_code, r.content))
return False
else:
data = r.json()
return data
def post_sample_data(key, iv):
fake_device_id = "MB88"
Load_VA_Total_Mean = random.randint(1000, 100000)
print('Data that should come back: {}'.format(Load_VA_Total_Mean))
data = {'i': fake_device_id, 'p': [
{'d': [54.3, 0, 99, 49.35, 3, 99, 51.533, 1, 98, 28964, 7348, 43590, Load_VA_Total_Mean, 10350, 55200, 49.7],
't': time.time(), 'dt': 'p'}]}
url = baseurl + '/realtimedata'
encryption_key_reference = 1
payload = '{}n{}'.format(convert_pack(data, key, iv), encryption_key_reference)
return http_post(url, payload)
def convert_pack(inputdict, key, iv):
jsonpayload = json.dumps(inputdict) # encode dict to json string
gzippayload = gzip.compress(jsonpayload.encode('utf-8')) # compress with gzip
encryptedpayload = base64.b64encode(encrypt(key, iv, message))
encoded = base64.b64encode(encryptedpayload)
print('encoded: {}'.format(encoded))
return str(encoded, encoding='utf-8')
def _pad_string(value):
length = len(value)
pad_size = BLOCK_SIZE - (length % BLOCK_SIZE)
return value.ljust(length + pad_size, 'x00')
def encrypt(key, iv, plaintext):
aes = AES.new(key, MODE, iv, segment_size=SEGMENT_SIZE)
plaintext = _pad_string(plaintext)
encrypted_text = aes.encrypt(plaintext)
return encrypted_text
post_sample_data(key, iv)
服务器代码:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"compress/gzip"
"io/ioutil"
"bytes"
)
func main() {
receivedText := "amZzRUR2NHVtcVpiZHNROHJiTTNYeGdUSndGTlVDZC9jaElSK1lXcFlJOD0="
fmt.Println("encrypted + encoded + gzipped: ", originalText)
key := []byte("TfvY7I358yospfWKcoviZizOShpm5hyH")
text := decrypt(key, originalText)
fmt.Println("decrypted: ", string(text))
reader := bytes.NewReader(text)
gzReader, err1 := gzip.NewReader(reader)
fmt.Println(gzReader)
if err1 != nil {
fmt.Println("error1")
}
content, err2 := ioutil.ReadAll(gzReader)
if err2 != nil {
fmt.Println("error2")
}
fmt.Println(string(content))
}
func decrypt(key []byte, cryptoText string) []byte {
ciphertext, _ := base64.StdEncoding.DecodeString(cryptoText)
fmt.Println("decoded: ", string(ciphertext))
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
iv := []byte("mb13KcoviZizvYhp")
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(ciphertext, ciphertext)
return ciphertext
}
输出:
<nil>
error1
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x288 pc=0x10a9167]
goroutine 1 [running]:
io/ioutil.readAll.func1(0xc420037dd0)
/usr/local/go/src/io/ioutil/ioutil.go:30 +0x119
panic(0x10c4580, 0x1154d00)
/usr/local/go/src/runtime/panic.go:489 +0x2cf
compress/gzip.(*Reader).Read(0x0, 0xc420092000, 0x200, 0x200, 0x1024ade, 0xc400000008, 0xc4200120c0)
/usr/local/go/src/compress/gzip/gunzip.go:247 +0x37
bytes.(*Buffer).ReadFrom(0xc420037d28, 0x11451a0, 0x0, 0xc420092000, 0x0, 0x200)
/usr/local/go/src/bytes/buffer.go:179 +0x160
io/ioutil.readAll(0x11451a0, 0x0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/io/ioutil/ioutil.go:33 +0x150
io/ioutil.ReadAll(0x11451a0, 0x0, 0x1, 0x7, 0x0, 0x0, 0x20)
/usr/local/go/src/io/ioutil/ioutil.go:42 +0x3e
main.main()
/Users/bkaankuguoglu/Desktop/Go-dev/tool-backend/tester.go:43
+0x404
exit status 2
问题是您传递给gz.NewReader()
的阅读器生成的"内容"不是有效的 gzip 流(数据(。如果gzip.NewReader()
返回非nil
错误(就像在您的情况下一样(,则返回的gzReader
可能会nil
(通常是(。
如果将有效的 gzip 流传递给gzip.NewReader()
,则返回的gzReader
将不会nil
,并且解码将成功。
例如,文本"hello"
的 gzip 编码形式为:
[31 139 8 0 0 0 0 0 0 255 203 72 205 201 201 7 0 134 166 16 54 5 0 0 0]
使用此作为输入:
data := []byte{31, 139, 8, 0, 0, 0, 0, 0, 0,
255, 203, 72, 205, 201, 201, 7, 0, 134, 166, 16, 54, 5, 0, 0, 0}
reader := bytes.NewReader(data)
// The rest is unchanged
它可以工作,输出是(在Go Playground上尝试(:
&{[31 139 8 0 0 0 0 0 0 255 203 72 205 201 201 7 0 134 166 16 54 5 0 0 0] 0 -1}
&{{ [] 0001-01-01 00:00:00 +0000 UTC 255} 0x10440260 0x10462000 0 0 [31 139 8 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] <nil> true}
hello