问题描述
问题:
我已经为我的兄弟做了一个主页,可以在这里访问:
http://www.daniel-steiger.ch
I've made a homepage for my brother, accessible here:
http://www.daniel-steiger.ch
它在 Linux 上使用 Microsoft ASP.NET MVC3 和 mono 3,通过 fastcgi 和 nginx(加上我自己的 DNS 服务器).
It uses Microsoft ASP.NET MVC3 on Linux with mono 3, over fastcgi with nginx (plus my own DNS server).
现在我知道这是一个不寻常的星座,但到目前为止,一切正常.
但是,我遇到了一个非常微妙的小错误.
Now I know this is an unusual constellation, but so far, it all works fine.
However, I ran into a minor very subtle bug.
当在图库中单击缩略图时,我想通过图库控制器的 FullImage 方法在新选项卡中显示全尺寸图像.
比如这个直接url:
http://www.daniel-steiger.ch/gallery/FullImage/001.jpg
在 Internet Explorer 中,我将图像改为文本.
在所有其他浏览器中显示无效图像"消息.
我通过直接文件 URL 调用图像解决了这个问题,效果很好:
http://www.daniel-steiger.ch/内容/图像/画廊/001.jpg?LastWriteTimeUTC=1358694795000
When in the gallery one clicks on a thumbnail image, I wanted to display the full-sized image via the FullImage method of the gallery controller in a new tab.
For example, this direct url:
http://www.daniel-steiger.ch/gallery/FullImage/001.jpg
In internet Explorer, I got the image as text instead.
In all other browsers displayed an "invalid image" message.
I solved the problem by calling the image via it's direct file URL, which works fine:
http://www.daniel-steiger.ch/Content/images/gallery/001.jpg?LastWriteTimeUTC=1358694795000
随后,我向单声道邮件列表报告了该错误
http://mono.1490590.n4.nabble.com/Bug-in-mono-3-0-1-MVC3-File-FileResult-td4658382.html
Subsequently, I reported the bug to the mono mailing list
http://mono.1490590.n4.nabble.com/Bug-in-mono-3-0-1-MVC3-File-FileResult-td4658382.html
现在我得到回应,这都是我的错,因为我设置了错误的图像 mime 类型,这是/是真的.
但是,我发现奇怪的是,如果是这样的话,相同的代码在 Windows 上也能正常工作,而且像 Chrome 这样的智能浏览器通常会检测到错误的 mime 设置并使用正确的设置.
Now I got as a response, that this is all my fault, because I set the wrong image mime type, which is/was true.
However, I found it strange that if that was the case, the same code works fine on Windows, plus smart browsers like Chrome usually detect a wrong mime setting and use the correct one.
于是我将mime-type从image/jpg"更改为image/jpeg",并将项目重新部署到服务器.
如果图像实际上是 jpeg 图像,我还使用文件实用程序检查了它.
So I changed the mime-type from "image/jpg" to "image/jpeg", and redeployed the project to the server.
I also checked with the file utility if the image is actually a jpeg image, and it is.
奇怪的是还是不显示图片.
在 Internet Explorer 上,我现在得到不可用".
在所有其他浏览器上,我得到:图像无法显示,因为它包含错误.
What is strange is that it still doesn't show the image.
On internet explorer, I now get "not available".
On all other browsers, I get: the image cannot be displayed because it contains errors.
我现在确实从图像包含错误的 URL 中获取图像.
wget http://www.daniel-steiger.ch/gallery/fullimage/001.jpg
I did now wget the image from the URL where the image contains errors.
wget http://www.daniel-steiger.ch/gallery/fullimage/001.jpg
然后我对无效文件和原始文件进行了二进制比较:
Then I ran a binary compare between the invalid and the original file:
cmp -l 001.jpg 001a.jpg | awk '{printf "%08X %02X %02X
", $1, strtonum(0$2), strtonum(0$3)}' >> comparison.txt
这是比较结果:
让我眼前一亮的是,Internet Explorer 说他找不到的图像实际上是 1.7 MB 大小,并且包含额外的字节:
What springs into my eye, is that the image that internet explorer says he cannot find is actually 1.7 MB in size, and contains the extra bytes:
31 39 36 62 36 38 0D 0A
一开始...
任何人都知道这里出了什么问题/这些字节可能来自哪里(除了它很可能来自 mono/fastcgi 中的错误)?
at the beginning...
Anybody has an idea what's going wrong here/ where these bytes could come from (apart from the fact that it's most likely from a bug in mono/fastcgi) ?
顺便说一句,这是新的控制器代码:
This is the new controller code btw:
namespace Homepage.Controllers
{
public class GalleryController : Controller
{
protected static string GetImageDirectory()
{
string bd = AppDomain.CurrentDomain.BaseDirectory;
string strImageDirectory = System.IO.Path.Combine(bd,
"Content");
strImageDirectory =
System.IO.Path.Combine(strImageDirectory, "images");
strImageDirectory =
System.IO.Path.Combine(strImageDirectory, "gallery");
return strImageDirectory;
} // End Function GetImageDirectory
protected static string strImageDirectory = GetImageDirectory();
public FileResult FullImage(string id)
{
string strFileName =
System.IO.Path.Combine(strImageDirectory, id);
//return new FilePathResult("CorrectFullPathAndFileName", "CorrectMime");
//return File(strFileName, "image/jpg"); // Old
return File(strFileName, "image/jpeg"); // New
} // End Action FullImage
public FileResult Thumb(string id)
{
//return Redirect(id);
string strFileName =
System.IO.Path.Combine(strImageDirectory, id);
System.IO.Stream ms =
Tools.Imaging.GetThumbnailStream(strFileName,
System.Drawing.Imaging.ImageFormat.Png);
return File(ms, "image/png");
/*
using (System.IO.Stream ms =
Tools.Imaging.GetThumbnailStream(strFileName,
System.Drawing.Imaging.ImageFormat.Png))
{
return File(ms, "image/png");
}*/
} // End Action Thumb
} // End Class GalleryController : Controller
} // End Namespace Homepage.Controllers
它变得陌生:
还有一个带有
it gets stranger:
There is also an extra sequence with
0d 0a 0d 0a 30 0d 0a 0d 0a
最后...
我刚刚做了 hexdump,发现原来的文件有文件大小(屏住呼吸):
I just did the hexdump, and found the original file has filesize (hold your breath):
00196b68
这里是十六进制转储(每个 8 MB):
规范格式(hexdump -C 001.jpg > 001.txt):
原始文件:http://www.daniel-steiger.ch/001.txt
拙劣的文件:http://www.daniel-steiger.ch/001a.txt
纯转储(hexdump 001.jpg > 001_1.txt):
原始文件:http://www.daniel-steiger.ch/001_1.txt
拙劣的文件:http://www.daniel-steiger.ch/001a_1.txt
Here the hexdumps (8 MB each):
Canonical format (hexdump -C 001.jpg > 001.txt):
Original file: http://www.daniel-steiger.ch/001.txt
Botched file: http://www.daniel-steiger.ch/001a.txt
Pure dump (hexdump 001.jpg > 001_1.txt):
Original file: http://www.daniel-steiger.ch/001_1.txt
Botched file: http://www.daniel-steiger.ch/001a_1.txt
嗯,拙劣文件的十六进制转储为 5 MB,原始文件的转储为 8.2 MB...
Hmmm, the hex dump for the botched files is 5 MB, the one for the original is 8.2 MB...
我用的是最新稳定的nginx:
I use the latest stable nginx:
sudo -s
nginx=stable # use nginx=development for latest development version
add-apt-repository ppa:nginx/$nginx
apt-get update
apt-get install nginx
Tools.Imaging 的完整代码(同时将 Tools 重命名为 MvcTools,以匹配程序集命名空间)
The full code for Tools.Imaging (renamed Tools to MvcTools in the meantime, to match the assembly namespace)
using System;
using System.Text;
namespace MvcTools
{
public class Imaging
{
//public static System.Drawing.Size m_sMaxThumbNailDimensions = new System.Drawing.Size(200, 200);
public static System.Drawing.Size m_sMaxThumbNailDimensions = new System.Drawing.Size(300, 300);
public static System.IO.Stream GetImageAsStream(
string strOrgFileName
, System.Drawing.Imaging.ImageFormat ifOutputFormat
)
{
return GetImageAsStream(strOrgFileName, ifOutputFormat, 1024);
} // End Function GetImage
public static System.IO.Stream GetImageAsStream(
string strOrgFileName
,System.Drawing.Imaging.ImageFormat ifOutputFormat
,int rez
)
{
System.IO.MemoryStream ms = null;
if (!System.IO.File.Exists(strOrgFileName))
throw new System.IO.FileNotFoundException(strOrgFileName);
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
ms = new System.IO.MemoryStream();
imgSourceImage.Save(ms, ifOutputFormat);
ms.Position = 0;
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.GetType().ToString());
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
return ms;
} // End Function GetImageAsStream
public static System.Drawing.Size GetThumbnailSize(string strOrgFileName)
{
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
decimal decPixToSubstract = 0;
decimal decPercentage;
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
return sThumbNailSizeToUse;
} // End Sub GetThumbnailSize(string strOrgFileName)
// http://stackoverflow.com/questions/7319842/mvc3-razor-thumbnail-resize-image-ideas
// http://stackoverflow.com/questions/1528525/alternatives-to-system-drawing-for-use-with-asp-net/1528908#1528908
public static void GenerateThumbnailFile(
string strPhysicalPath,
string strOrgFileName, string strThumbnailFileName,
System.Drawing.Imaging.ImageFormat ifOutputFormat, int rez
)
{
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
//System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);
decimal decPixToSubstract = 0;
decimal decPercentage;
//default
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
using (System.Drawing.Bitmap bmpThumbnail = new System.Drawing.Bitmap(sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height))
{
bmpThumbnail.SetResolution(rez, rez);
using (System.Drawing.Image imgThumbNail = bmpThumbnail)
{
using (System.Drawing.Graphics gGraphicsContext = System.Drawing.Graphics.FromImage(imgThumbNail))
{
gGraphicsContext.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gGraphicsContext.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gGraphicsContext.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
System.Drawing.Rectangle rThumbnailDimension = new System.Drawing.Rectangle(0, 0, sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height);
gGraphicsContext.DrawImage(imgSourceImage, rThumbnailDimension);
} // End Using gGraphicsContext
imgThumbNail.Save(System.IO.Path.Combine(strPhysicalPath, strThumbnailFileName), ifOutputFormat);
} // End Using imgThumbNail
} // End Using bmpThumbnail
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
} // End Function GenerateThumbNail
public static System.IO.Stream GetThumbnailStream(
string strOrgFileName
, System.Drawing.Imaging.ImageFormat ifOutputFormat
)
{
return GetThumbnailStream(strOrgFileName, ifOutputFormat, 1024);
} // End Function GetThumbnailStream
public static System.IO.Stream GetThumbnailStream(
string strOrgFileName
,System.Drawing.Imaging.ImageFormat ifOutputFormat
,int rez
)
{
System.IO.MemoryStream ms = null;
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
decimal decPixToSubstract = 0;
decimal decPercentage;
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
using (System.Drawing.Bitmap bmpThumbnail = new System.Drawing.Bitmap(sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height))
{
bmpThumbnail.SetResolution(rez, rez);
using (System.Drawing.Image imgThumbNail = bmpThumbnail)
{
using (System.Drawing.Graphics gGraphicsContext = System.Drawing.Graphics.FromImage(imgThumbNail))
{
gGraphicsContext.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gGraphicsContext.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gGraphicsContext.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
System.Drawing.Rectangle rThumbnailDimension = new System.Drawing.Rectangle(0, 0, sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height);
gGraphicsContext.DrawImage(imgSourceImage, rThumbnailDimension);
ms = new System.IO.MemoryStream();
imgThumbNail.Save(ms, ifOutputFormat);
ms.Position = 0;
} // End Using gGraphicsContext
} // End Using imgThumbNail
} // End Using bmpThumbnail
/*
byte[] buffer = null;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
imgThumbNail.Save(ms, ifOutputFormat);
buffer = ms.ToArray();
}
*/
// Exerts from Page_Load method
//Response.ContentType = "image/" + extension;
//Response.OutputStream.Write(pBuffer, 0, pBuffer.Length);
//Response.End();
//imgThumbNail.Save(System.IO.Path.Combine(strPhysicalPath, strThumbnailFileName), ifOutputFormat);
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
//System.Windows.Forms.MessageBox.Show("image/" + ifOutputFormat.ToString().ToLower());
return ms;
} // End Function GenerateThumbNail
} // End Class Imaging
} // End Namespace Tools
推荐答案
这似乎是一个涉及 Chunked传输编码 in
This seems to be a bug involving Chuncked transfer encoding in
Class: System.Web.HttpResponse (or one of its dependencies)
Method: TransmitFile(string filename)
构造函数中有这段代码:
There is this code in the constructor:
if (worker_request != null)
use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
修补它以检查 CGI(如果是 CGI,则服务器处理文件传输,因此可能没有根据 RFC 3875.
Patched it to check for CGI (if CGI, the server handles the file transfer, so there may be no chuncked encoding given back from the FastCGI server as per RFC 3875.
internal HttpResponse (HttpWorkerRequest worker_request, HttpContext context) : this ()
{
WorkerRequest = worker_request;
this.context = context;
#if !TARGET_J2EE
if (worker_request != null)
{
if(worker_request.GetHttpVersion () == "HTTP/1.1")
{
string GatewayIface = context.Request.ServerVariables["GATEWAY_INTERFACE"];
use_chunked = (GatewayIface == null || !GatewayIface.StartsWith("CGI"));
}
else
use_chunked = false;
}
#endif
writer = new HttpWriter (this);
}
添加补丁到https://bugzilla.xamarin.com/show_bug.cgi?id=10001
在单声道 3.2.3 中修复
Added patch to
https://bugzilla.xamarin.com/show_bug.cgi?id=10001
Fixed in mono 3.2.3
这篇关于为什么我在图像的开头有不需要的额外字节?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!