【发布时间】:2015-01-29 15:24:23
【问题描述】:
我正在尝试让 TinyMCE、gzip 和缓存正常工作,但遇到浏览器无法缓存对 gzip.ashx 处理程序的请求的问题。
我的设置:
- TinyMCE(目前4.1.7)
- TinyMCE Compressor (.NET 4.0.1)
- ASP.NET WebForm 应用程序/IIS。
这是我的代码(非常标准):
<!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>
页面的首次加载:
-
tinymce.gzip.js请求 TinyMCE 压缩机tinymce.gzip.ashx -
tinymce.gzip.ashx压缩所有 TinyMCE javascript 文件并生成一个压缩文件 (.gz),如tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz
页面的后续加载:
-
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 的。
这是我尝试过的:
我尝试像http://mysite/scripts/tinymce/tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz 一样直接请求gzip,但我仍然收到
200 OK手动设置
Response.StatusCode = 304;只会导致响应为空而不加载tinymce。执行
<script src="/scripts/tinymce/tinymce.gzip-C3F36E9F5715BFD1943ECF340F1AB753.gz"></script>将返回.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