#c# #asp.net #gzip
#c# #asp.net #gzip
Вопрос:
Предыстория
Я настраиваю общий обработчик для:
- Объединяйте и сжимайте файлы Javascript и CSS
- Кэшируйте версию GZip и версию, отличную от GZip
- Предоставьте соответствующую версию на основе запроса
Я работаю в MonoDevelop версии v2.8.2 на OSX 10.7.2
Проблема
Поскольку я хочу кэшировать архивированную версию, мне нужно архивировать без использования фильтра ответов
Используя этот код, я могу успешно сжимать и распаковывать строку на сервере, но когда я отправляю ее клиенту, я получаю:
- Ошибка 330 (net::ERR_CONTENT_DECODING_FAILED): неизвестная ошибка. (Chrome)
- Не удается декодировать необработанные данные (Safari)
- Страница, которую вы пытаетесь просмотреть, не может быть показана, поскольку она использует недопустимую или неподдерживаемую форму сжатия. (Firefox)
Соответствующий код
string sCompiled =null;
if(bCanGZip)
{
context.Response.AddHeader("Content-Encoding", "gzip");
bHasValue = CurrentCache.CompiledScripts.TryGetValue(context.Request.Url.ToString() "GZIP", out sCompiled);
}
//...
//Process files if bHasVale is false
//Compress result of file concatination/minification
//Compression method
public static string CompressString(string text)
{
UTF8Encoding encoding = new UTF8Encoding(false);
byte[] buffer = encoding.GetBytes(text);
using(MemoryStream memoryStream = new MemoryStream()){
using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
memoryStream.Position = 0;
byte[] compressedData = new byte[memoryStream.Length];
memoryStream.Read(compressedData, 0, compressedData.Length);
byte[] gZipBuffer = new byte[compressedData.Length 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
return Convert.ToBase64String(gZipBuffer);
}
}
//...
//Return value
switch(Type){
case FileType.CSS:
context.Response.ContentType = "text/css";
break;
case FileType.JS:
context.Response.ContentType = "application/javascript";
break;
}
context.Response.AddHeader("Content-Length", sCompiled.Length.ToString());
context.Response.Clear();
context.Response.Write(sCompiled);
Пытается разрешить
Поскольку я не уверен, какие строки:
byte[] gZipBuffer = new byte[compressedData.Length 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
выполняются, я попытался их удалить.
Я пробовал играть с разными кодировками / параметрами.
На данный момент я действительно не уверен, как решить проблему, поскольку я не знаю источник ошибки (кодирование / сжатие / другое).
Любая помощь была бы очень признательна!
Другие ресурсы, которые я нашел по этому вопросу
- http://beta.blogs.microsoft.co.il/blogs/mneiter/archive/2009/03/24/how-to-compress-and-decompress-using-gzipstream-object.aspx
- http://madskristensen.net/post/Compress-and-decompress-strings-in-C.aspx
- http://www.codeproject.com/KB/files/GZipStream.aspx
- http://www.codeproject.com/KB/aspnet/HttpCombine.aspx
- http://webreflection .blogspot.com/2009/01/quick-tip-c-gzip-content.html
- http://www.dominicpettifer.co.uk/Blog/17/gzip-compress-your-websites-html-css-script-in-code
Комментарии:
1. Упомянутые вами строки предназначены для создания фрагмента сжатых данных, состоящего из а) длины блока б) фактических данных. Я понятия не имею, как спецификации работают на таком низком уровне, но если эти строки есть, то в последней следует скорее сказать
return Convert.ToBase64String( gZipBuffer )
. Однако странно то, что фактические данные предшествовали длине блока, в то время как моя интуиция подсказывает мне, что должно быть наоборот.2. @WiktorZychla — спасибо за понимание. Я забавлялся с пропуском этой части кода, поэтому возвращалась неправильная переменная.
Ответ №1:
Это одна из тех вещей, когда, объяснив свою проблему, вы быстро находите ответ.
Мне нужно записать ответ в двоичном формате. Таким образом, модифицируя алгоритм сжатия, чтобы вернуть массив байтов:
public static byte[] CompressStringToArray(string text){
UTF8Encoding encoding = new UTF8Encoding(false);
byte[] buffer = encoding.GetBytes(text);
using(MemoryStream memoryStream = new MemoryStream()){
using (GZipStream gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
memoryStream.Position = 0;
byte[] compressedData = new byte[memoryStream.Length];
memoryStream.Read(compressedData, 0, compressedData.Length);
return compressedData;
}
}
и затем вызывает:
//Writes a byte buffer without encoding the response stream
context.Response.BinaryWrite(GZipTools.CompressStringToArray(sCompiled));
Решает проблему. Надеюсь, это поможет другим, кто столкнется с такой же проблемой.
Комментарии:
1. я все сделал правильно, но использовал repsonse.write, binarywrite решил мою проблему 1 🙂