4
votes

I have a windows 8 application connecting to a web service written in Node.js. On the windows 8 side I compressed my request body to gzip. But on the Node.js side I found that my req.body type was Object.

I cannot use zlib to uncomporess the body since it's not a stream.

I can use zlib to uncomporess the req, but I don't know how to retrieve the req.body content from the unzipped stream and parse the body in JSON format.

BTW, I reviewed my request through Fiddler and it told me the request body was gzipped, and I can see my raw body through Fiddler after unzipped so the request should be correct.

Updated Below is my Node.js app

(function () {
    var express = require("express");
    var zlib = require("zlib");

    var app = express();
    var port = 12345;

    app.configure(function () {
        app.use(express.compress());
        app.use(express.bodyParser());
    });

    app.post("/test", function (req, res) {
        var request = req.body;
        req.pipe(zlib.createGunzip());

        var response = {
            status: 0,
            value: "OK"
        };
        res.send(200, response);
    });

    console.log("started at port %d", port);
    app.listen(port);
})();

And below is my windows store app code (partial)

        private async void button1_Click_1(object sender, RoutedEventArgs e)
        {
            var message = new
            {
                Name = "Shaun",
                Value = "12345678901234567890123456789012345678901234567890"
            };
            var json = await JsonConvert.SerializeObjectAsync(message, Formatting.Indented);
            var bytes = Encoding.UTF8.GetBytes(json);

            var client = new HttpClient();
            client.BaseAddress = new Uri("http://192.168.56.1:12345/");
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.ExpectContinue = false;
            var jsonContent = new JsonContent(message);
            var gzipContent = new GZipContent3(jsonContent);
            var res = await client.PostAsync("test", gzipContent);

            var dialog = new Windows.UI.Popups.MessageDialog(":)", "完成");
            await dialog.ShowAsync();
        }


        internal class GZipContent3 : ByteArrayContent
        {
            public GZipContent3(HttpContent content)
                : base(LoadGZipBytes(content))
            {
                //base.Headers.ContentType = content.Headers.ContentType;
                base.Headers.ContentType = new MediaTypeHeaderValue("x-application/x-gzip");
                base.Headers.ContentEncoding.Add("gzip");
            }

            private static byte[] LoadGZipBytes(HttpContent content)
            {
                var source = content.ReadAsByteArrayAsync().Result;
                byte[] buffer;
                using (var outStream = new MemoryStream())
                {
                    using (var gzip = new GZipStream(outStream, CompressionMode.Compress, true))
                    {
                        gzip.Write(source, 0, source.Length);
                    }
                    buffer = outStream.ToArray();
                }
                return buffer;
            }
        }


        internal class JsonContent : StringContent
        {
            private const string defaultMediaType = "application/json";

            public JsonContent(string json)
                : base(json)
            {
                var mediaTypeHeaderValue = new MediaTypeHeaderValue(defaultMediaType);
                mediaTypeHeaderValue.CharSet = Encoding.UTF8.WebName;
                base.Headers.ContentType = mediaTypeHeaderValue;
            }

            public JsonContent(object content)
                : this(GetJson(content))
            {
            }

            private static string GetJson(object content)
            {
                if (content == null)
                {
                    throw new ArgumentNullException("content");
                }
                var json = JsonConvert.SerializeObject(content, Formatting.Indented);
                return json;
            }
        }
2
it would be helpful if you can post relevant part of your codevinayr
@Shaun Xu, did you able to uncompress the request? Could you share that code?Chan Le

2 Answers

1
votes

http://www.senchalabs.org/connect/json.html. Basically you need to write your own middleware based on connect.json() that pipes through an uncompression stream like connect.compress() but the opposite direction: http://www.senchalabs.org/connect/compress.html

Also, make sure you're sending the correct Content-Encoding header in your request.

If you show me what you have so far I can help you further.

1
votes

I was working on similar thing and finally landed on

function getGZipped(req, callback) {
    var gunzip = zlib.createGunzip();
    req.pipe(gunzip);

    var buffer  = [];
    gunzip.on('data', function (data) {
        // decompression chunk ready, add it to the buffer
        buffer.push(data);
    }).on('end', function () {
        //response and decompression complete, join the buffer and return
        callback(null, JSON.parse(buffer));
    }).on('error', function (e) {
        callback(e);
    });
}