1

我正在开发一个包含树视图的 ASP.NET (3.5) 网站;节点的值设置为 PDF 文件的文件路径(在服务器上)。当用户点击树节点时,服务器端代码获取节点值(文件路径),创建一个 FileInfo 对象,并(在正确设置所有标头 Content-type、Cache-Control 等后)调用 Response.TransmitFile( xxxxpath) 发送到用户的浏览器。

这适用于主流浏览器、主要设备(PC、Mac、iOS 设备)。该文件正确下载并在用户的机器上打开。但在某些设备和某些浏览器上,无法打开 PDF 文件。在 Android 设备上,Firefox 似乎可以正确下载并打开 PDF,但普通的 Android 浏览器不能。在 Kindle Fire 上,Silk 浏览器似乎成功下载了文件,但是在尝试打开它时,我看到一个错误:“找不到 PDF 预告片”......或者它说 PDF 受 DRM 保护(它是不是)。我还没有在 Fire 上尝试过其他浏览器(如果有的话)。

我已经尝试在静态 HTML 标记中使用锚链接,当以这种方式访问​​时,问题浏览器似乎可以正确下载和显示 PDF。当通过代码完成时,ASP.NET 向浏览器发送响应的方式似乎存在问题(不一致?)。我使用过 Response.Flush、Response.WriteFile、Response.BinaryWrite、Response.Close、Response.End 等,它们都产生相同的结果:大多数浏览器处理文件,但有些浏览器无法处理 PDF。

那么,ASP.NET 构造某些浏览器不喜欢的 Response 对象(尤其是在发回 PDF 时)的方式是否存在一些问题?TIA。

4

1 回答 1

1

很简单,您的问题的答案是“否”。如果您对自己的操作是否正确有疑问,您可能需要发布您的代码;否则:“不”。:)

我认为您提到的浏览器比写入响应流这样简单和成熟的浏览器更令人怀疑。

作为参考,这是我使用 iHttpHandler 进行的一种经过验证的真实方法:

    public void ProcessRequest(System.Web.HttpContext context)
    {
        string sFilePath = context.Server.MapPath(String.Concat("~/App_LocalResources", context.Request.QueryString["path"]));
        try
        {
            context.Response.Clear();
            context.Response.ContentType = "application/octet-stream";

            int iReadLength = 16384;
            int iLastReadLength = iReadLength;
            byte[] buffer = new byte[iReadLength];
            if (System.IO.File.Exists(sFilePath))
            {
                System.IO.FileInfo fInfo = new System.IO.FileInfo(sFilePath);
                context.Response.AddHeader("Content-Length", fInfo.Length.ToString());
                context.Response.AddHeader("Content-Disposition", String.Format("attachment; filename=\"{0}\"", fInfo.Name));
                using (System.IO.FileStream input = new System.IO.FileStream(sFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    try
                    {
                        while (iLastReadLength > 0 && context.Response.IsClientConnected)
                        {
                            iLastReadLength = input.Read(buffer, 0, iLastReadLength);

                            if (iLastReadLength > 0)
                            {
                                context.Response.OutputStream.Write(buffer, 0, iLastReadLength);
                                context.Response.OutputStream.Flush();
                            }
                        }
                        context.Response.Flush();
                    }
                    catch
                    {
                    }
                    finally
                    {
                        input.Close();
                    }
                }
            }
        }
        catch
        {
        }
        finally
        {
        }
    }

由于您已经表明您正在从另一个地方提取文件,因此这里是如何将其写入内存流的方法。只需从远程服务器(或文件流,Sql Binary Reader,w/e)中提取您的响应流,然后重置您的 MemoryStream 位置,然后使用上面的功能将您的响应流写入客户端。

int iReadLength = 16384;
long lLastReadLength = iReadLength;
long lDataIndex = 0;
byte[] buffer = new byte[iReadLength];
using (System.IO.MemoryStream msTemp = new System.IO.MemoryStream())
{
    while (lLastReadLength > 0)
    {
        lLastReadLength = reader.GetBytes(0, lDataIndex, buffer, 0, iReadLength);
        lDataIndex += lLastReadLength;

        if (lLastReadLength > 0)
        {
            msTemp.Write(buffer, 0, Convert.ToInt32(lLastReadLength));
            msTemp.Flush();
        }
    }

    // Reset Memory Position
    msTemp.Position = 0;

    // Now write to the Response Stream here
}
于 2012-10-01T02:03:37.137 回答