服务器无法在HTTP头已发送后添加标头 c# excel 内联

4

我在尝试返回Excel内联响应时遇到了问题。

我已经搜索了所有的编码帮助页面,但仍然找不到有效的解决方案。

下面是我制作的一个简化示例,这个问题总是发生。

错误出现在这一行:

Line 56:         Response.AddHeader("content-disposition",

代码后台:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        PleaseWait();
        Call();
    }

    protected void Call()
    {
        strSql = "SELECT * FROM ....... ; ";

        SqlCommand cmd = new SqlCommand(strSql);
        DataTable dt = GetData(cmd);

        GridView GridView1 = new GridView();
        GridView1.AllowPaging = false;
        GridView1.DataSource = dt;
        GridView1.DataBind();

        Response.Clear();
        Response.Buffer = true;
        Response.BufferOutput = true;
        Response.ClearHeaders();

        Response.AddHeader("content-disposition",
         "attachment;filename= "Output.xls");
        Response.Charset = "";
        Response.ContentType = "application/vnd.ms-excel";
        StringWriter sw = new StringWriter();
        HtmlTextWriter hw = new HtmlTextWriter(sw);

        for (int i = 0; i < GridView1.Rows.Count; i++)
        {
            GridView1.Rows[i].Attributes.Add("class", "textmode");
        }
        GridView1.RenderControl(hw);

        string style = @"<style> .textmode { mso-number-format:\@; } </style>";
        Response.Write(style);
        Response.Output.Write(sw.ToString());
        Response.Flush();
        Response.End();
    }

    protected void PleaseWait()
    {
        this.Response.Write("<meta http-equiv=X-UA-Compatible content=IE=8>");
        this.Response.Write(@"<style type=text/css media=all>");
        this.Response.Write(@".loading");
        this.Response.Write(@"{");
        this.Response.Write(@"text-align: center;");
        this.Response.Write(@"padding-top: 30px;");
        this.Response.Write(@"border-width: 1px solid #000;");
        this.Response.Write(@"width: 300px;");
        this.Response.Write(@"height: 100px;");
        this.Response.Write(@"-ms-filter: alpha(opacity=90);");
        this.Response.Write(@"-ms-opacity: 0.90;");
        this.Response.Write(@"border-style: solid;");
        this.Response.Write(@"background-color: #FFFFFF;");
        this.Response.Write(@"position: absolute;");
        this.Response.Write(@"font-family: Trebuchet MS;");
        this.Response.Write(@"font-size: small;");
        this.Response.Write(@"position: absolute;");
        this.Response.Write(@"top: 0;");
        this.Response.Write(@"bottom: 0;");
        this.Response.Write(@"left: 0;");
        this.Response.Write(@"right: 0;");
        this.Response.Write(@"margin: auto;");
        this.Response.Write(@"display: block;");
        this.Response.Write(@"background: url('images/wait01.gif') no-repeat center;");
        this.Response.Write(@"}");
        this.Response.Write(@"</style>");

        this.Response.Write(@"<div id=mydiv class=loading>&nbsp;</div>");
        this.Response.Write(@"<script>mydiv.innerText = '';");
        this.Response.Write(@"</script>");
        this.Response.Write(@"<script language=javascript>;");
        this.Response.Write(@"var dots = 0;");
        this.Response.Write(@"var dotmax = 10;");
        this.Response.Write(@"function ShowWait()");
        this.Response.Write(@"{");
        this.Response.Write(@"var output;");
        this.Response.Write(@"output = 'Wait...';");
        this.Response.Write(@"dots++;");
        this.Response.Write(@"if(dots>=dotmax)dots=1;");
        this.Response.Write(@"for(var x = 0;");
        this.Response.Write(@"x < dots;x++)");
        this.Response.Write(@"{");
        this.Response.Write(@"output += '.';");
        this.Response.Write(@"}");
        this.Response.Write(@"mydiv.innerText =  output;");
        this.Response.Write(@"}");
        this.Response.Write(@"function StartShowWait()");
        this.Response.Write(@"{");
        this.Response.Write(@"mydiv.style.visibility = 'visible'; ");
        this.Response.Write(@"window.setInterval('ShowWait()',1500);");
        this.Response.Write(@"}");
        this.Response.Write(@"function HideWait()");
        this.Response.Write(@"{");
        this.Response.Write(@"mydiv.style.visibility = 'hidden';");
        this.Response.Write(@"window.clearInterval();");
        this.Response.Write(@"}");
        this.Response.Write(@"StartShowWait();");
        this.Response.Write(@"</script>");

        this.Response.Flush();
        Thread.Sleep(500);
    }

    private DataTable GetData(SqlCommand cmd)
    {
        DataTable dt = new DataTable();
        String strConnString = System.Configuration.ConfigurationManager.
             ConnectionStrings["conn"].ConnectionString;
        SqlConnection con = new SqlConnection(strConnString);
        SqlDataAdapter sda = new SqlDataAdapter();
        cmd.CommandType = CommandType.Text;
        cmd.Connection = con;
        try
        {
            con.Open();
            sda.SelectCommand = cmd;
            sda.Fill(dt);
            return dt;
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            con.Close();
            sda.Dispose();
            con.Dispose();
        }
    }

    public override void VerifyRenderingInServerForm(Control control)
    {
    }
}   
1个回答

5

是的,你不能这样做。在你的PleaseWait方法中,你调用了Response.Flush。这会发送当前缓冲的输出以及HTTP头信息。HTTP头信息总是在其他响应数据之前被发送,所以你运气不好。

通常的做法是有一个单独的PleaseWait页面,它会进行定时重定向到实际文件(然后只发送带有正确头信息的文件数据)。

基本问题是HTTP是“单个请求,单个响应”。你试图对单个请求返回两个响应,这在纯HTTP上是不可能的(遗憾的是;有类似HTTP的协议可以允许这种操作,但它们在浏览器中并没有得到真正的支持——当你可以一次性发送20个文件而不是分别发送20个请求时,它会大大提高性能)。


谢谢您的帮助。您有创建单独的PleaseWait页面并进行定时重定向到实际文件的示例吗? - Hamamelis
@user3370558 好的,你可以从“请稍候”页面简单地执行 Response.Redirect。你仍然需要将代码拆分成两个页面或根据查询字符串进行决策 - getData.aspx 可以显示“请稍候”,并重定向到 getData.aspx?download=1,这将运行 Call 而不是 PleaseWait - Luaan
在页面default.aspx中仅运行PleaseWait()并重定向到getData.aspx,在getData.aspx中仅运行Call()。 服务器无法在HTTP标头发送后附加标头,该行为第50行:Response.AddHeader("content-disposition"。 - Hamamelis
@user3370558 你是否真的在使用 Response.Redirect?听起来很像你正在使用 Server.Transfer。或者你之前使用了 Response.Flush,或者构建了大量数据(以便缓冲区自动刷新)。此外,请使用 Response.BufferOutput 而不是 Response.Buffer - Luaan
如果在 default.aspx 中使用 Response.Redirect,会出现错误 Cannot redirect after HTTP headers have been sent。使用 Server.Transfer 设置后,在 default.aspx 页面中不会出现错误,但在 gedData.aspx 页面中会出现错误。 - Hamamelis
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接