【问题标题】:TinyMCE, gzip and cachingTinyMCE、gzip 和缓存
【发布时间】:2015-01-29 15:24:23
【问题描述】:

我正在尝试让 TinyMCE、gzip 和缓存正常工作,但遇到浏览器无法缓存对 gzip.ashx 处理程序的请求的问题。

我的设置:

这是我的代码(非常标准):

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script src="/scripts/tinymce/tinymce.gzip.js"></script>
</head>
<body>
    <script>
        tinymce.init({
        selector: 'textarea',
        plugins: 'image link'
       });
    </script>   
    <textarea />
</body>
</html>

页面的首次加载:

  1. tinymce.gzip.js 请求 TinyMCE 压缩机 tinymce.gzip.ashx
  2. tinymce.gzip.ashx 压缩所有 TinyMCE javascript 文件并生成一个压缩文件 (.gz),如 tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz

页面的后续加载:

  1. tinymce.gzip.ashx 检查磁盘上是否存在 .gz 文件并将其返回给浏览器

我的 tinymce.gzip.ashx(帖子末尾的完整脚本)看起来像原来的,但有一些细微的变化,因为页面 diskcache 参数未在查询字符串中传递:

..
...
themes = GetParam("themes", "").Split(',');
diskCache = true; //GetParam("diskcache", "") == "true";
isJS = GetParam("js", "") == "true";
..

无论如何,这一切都很好,但真正的问题发生在浏览器缓存该 .gz 文件。我永远无法让它返回 HTTP/1.1 304 Not Modified 响应,因此不会再次请求 .gz。所有其他文件都是 304 的。

这是我尝试过的:

  1. 我尝试像http://mysite/scripts/tinymce/tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz 一样直接请求gzip,但我仍然收到200 OK

  2. 手动设置Response.StatusCode = 304;只会导致响应为空而不加载tinymce。

  3. 执行&lt;script src="/scripts/tinymce/tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz"&gt;&lt;/script&gt; 将返回.gz 文件但不加载TinyMCE

我已经为此花费了五个小时 - 感谢任何帮助。

以下是 IE 11.0.9600.17498、FF 35.01 和 Fiddler 的一些屏幕截图:

完整的 tinymce.gzip.ashx 处理程序:

<%@ WebHandler Language="C#" Class="Handler" %>
/**
 * tinymce.gzip.ashx
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://tinymce.moxiecode.com/license
 * Contributing: http://tinymce.moxiecode.com/contributing
 *
 * This file compresses the TinyMCE JavaScript using GZip and
 * enables the browser to do two requests instead of one for each .js file.
 *
 * It's a good idea to use the diskcache option since it reduces the servers workload.
 */

using System;
using System.Web;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

public class Handler : IHttpHandler {

private HttpResponse Response;
private HttpRequest Request;    
private HttpServerUtility Server;

public void ProcessRequest(HttpContext context) {
    this.Response = context.Response;
    this.Request = context.Request;
    this.Server = context.Server;
    this.StreamGzipContents();
}

public bool IsReusable {
    get {
        return false;
    }
}

#region private

private void StreamGzipContents() {
    string cacheKey = "", cacheFile = "", content = "", enc, suffix, cachePath;
    string[] plugins, languages, themes;
    bool diskCache, supportsGzip, isJS, compress, core;
    int i, x, expiresOffset;
    GZipStream gzipStream;
    Encoding encoding = Encoding.GetEncoding("windows-1252");
    byte[] buff;

    // Get input
    plugins = GetParam("plugins", "").Split(',');
    languages = GetParam("languages", "").Split(',');
    themes = GetParam("themes", "").Split(',');
    diskCache = true; //GetParam("diskcache", "") == "true";
    isJS = GetParam("js", "") == "true";
    compress = GetParam("compress", "true") == "true";
    core = GetParam("core", "true") == "true";
    suffix = GetParam("suffix", "min");
    cachePath = Server.MapPath("."); // Cache path, this is where the .gz files will be stored
    expiresOffset = 10; // Cache for 10 days in browser cache

    // Custom extra javascripts to pack
    string[] custom = {/*
        "some custom .js file",
        "some custom .js file"
    */};

    // Set response headers
    Response.ContentType = "text/javascript";
    Response.Charset = "UTF-8";
    Response.Buffer = false;

    // Setup cache
    Response.Cache.SetExpires(DateTime.Now.AddDays(expiresOffset));
    Response.Cache.SetCacheability(HttpCacheability.Public);
    Response.Cache.SetValidUntilExpires(false);

    // Vary by all parameters and some headers
    Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
    Response.Cache.VaryByParams["theme"] = true;
    Response.Cache.VaryByParams["language"] = true;
    Response.Cache.VaryByParams["plugins"] = true;
    Response.Cache.VaryByParams["lang"] = true;
    Response.Cache.VaryByParams["index"] = true;

    // Setup cache info
    if (diskCache) {
        cacheKey = GetParam("plugins", "") + GetParam("languages", "") + GetParam("themes", "");

        for (i = 0; i < custom.Length; i++)
            cacheKey += custom[i];

        cacheKey = MD5(cacheKey);

        if (compress)
            cacheFile = cachePath + "/tinymce.gzip-" + cacheKey + ".gz";
        else
            cacheFile = cachePath + "/tinymce.gzip-" + cacheKey + ".js";
    }

    // Check if it supports gzip
    enc = Regex.Replace("" + Request.Headers["Accept-Encoding"], @"\s+", "").ToLower();
    supportsGzip = enc.IndexOf("gzip") != -1 || Request.Headers["---------------"] != null;
    enc = enc.IndexOf("x-gzip") != -1 ? "x-gzip" : "gzip";

    // Use cached file disk cache
    if (diskCache && supportsGzip && File.Exists(cacheFile)) {
        Response.AppendHeader("Content-Encoding", enc);
        Response.WriteFile(cacheFile);
        return;
    }

    // Add core
    if (core) {
        content += GetFileContents("tinymce." + suffix + ".js");
    }

    // Add core languages
    for (x = 0; x < languages.Length; x++)
        content += GetFileContents("langs/" + languages[x] + ".js");

    // Add themes
    for (i = 0; i < themes.Length; i++) {
        content += GetFileContents("themes/" + themes[i] + "/theme." + suffix + ".js");

        for (x = 0; x < languages.Length; x++)
            content += GetFileContents("themes/" + themes[i] + "/langs/" + languages[x] + ".js");
    }

    // Add plugins
    for (i = 0; i < plugins.Length; i++) {
        content += GetFileContents("plugins/" + plugins[i] + "/plugin." + suffix + ".js");

        for (x = 0; x < languages.Length; x++)
            content += GetFileContents("plugins/" + plugins[i] + "/langs/" + languages[x] + ".js");
    }

    // Add custom files
    for (i = 0; i < custom.Length; i++)
        content += GetFileContents(custom[i]);

    // Generate GZIP'd content
    if (supportsGzip) {
        if (compress)
            Response.AppendHeader("Content-Encoding", enc);

        if (diskCache && cacheKey != "") {
            // Gzip compress
            if (compress) {
                using (Stream fileStream = File.Create(cacheFile)) {
                    gzipStream = new GZipStream(fileStream, CompressionMode.Compress, true);
                    buff = encoding.GetBytes(content.ToCharArray());
                    gzipStream.Write(buff, 0, buff.Length);
                    gzipStream.Close();
                }
            } else {
                using (StreamWriter sw = File.CreateText(cacheFile)) {
                    sw.Write(content);
                }
            }

            // Write to stream
            Response.WriteFile(cacheFile);
        } else {
            gzipStream = new GZipStream(Response.OutputStream, CompressionMode.Compress, true);
            buff = encoding.GetBytes(content.ToCharArray());
            gzipStream.Write(buff, 0, buff.Length);
            gzipStream.Close();
        }
    } else
        Response.Write(content);
}

private string GetParam(string name, string def) {
    string value = Request.QueryString[name] != null ? "" + Request.QueryString[name] : def;

    return Regex.Replace(value, @"[^0-9a-zA-Z\\-_,]+", "");
}

private string GetFileContents(string path) {
    try {
        string content;

        path = Server.MapPath(path);

        if (!File.Exists(path))
            return "";

        StreamReader sr = new StreamReader(path);
        content = sr.ReadToEnd();
        sr.Close();

        return content;
    } catch (Exception ex) {
        // Ignore any errors
    }

    return "";
}

private string MD5(string str) {
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] result = md5.ComputeHash(Encoding.ASCII.GetBytes(str));
    str = BitConverter.ToString(result);

    return str.Replace("-", "");
}

#endregion

}

【问题讨论】:

  • 您找到解决方案了吗?可以分享一下解决方法吗?
  • 是的。 Symeon 在下面的回答解决了这个问题。 ashx 处理程序受到一些预缓存代码的影响(此处未显示)。对于我的情况,我需要在我的 web.config 中排除处理程序问题已解决。

标签: asp.net webforms tinymce gzip http-caching


【解决方案1】:

在我看来,ashx 页面正在发送会话状态的 cookie - 如果您在 asp.net 中有 cookie,它不会缓存 - 我自己也去过那里。您可能可以从会话中排除该处理程序,并确保它没有设置任何 cookie。

【讨论】:

  • 感谢您的建议-我认为这正是需要做的-我找到了此链接geekytidbits.com/…-尚未实现此功能,但会在某个时候实现。我会给你加分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 2010-11-12
  • 2013-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多