Сжатие Javascript из .ashx возвращает ошибку декодирования в браузере

#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);
  

выполняются, я попытался их удалить.

Я пробовал играть с разными кодировками / параметрами.

На данный момент я действительно не уверен, как решить проблему, поскольку я не знаю источник ошибки (кодирование / сжатие / другое).

Любая помощь была бы очень признательна!

Другие ресурсы, которые я нашел по этому вопросу

Комментарии:

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 🙂