最近在做公司的一个内部管理系统,因为自己php不熟,公司又没有asp.net的环境,所以自己最后居然用js+CGI的模式,运行速度倒是飞快了,编码却麻烦的要死……罪过啊,罪过,又不是外网……
废话不多说了,有一个问题就是要在调用我的CGI的时候,返回一个文件下载对话框。
好吧,在网上搜了一下,实际上只是http头里面有这样一段就可以了:

Content-Disposition:   attachment;   filename= %s\r\n\r\n

找到了php版如下:

$old_name = “E:\a.doc”;
$file_name = “新文件名.doc”;
if (!file_exists($old_name)) { //检查文件是否存在
    echo “文件找不到”;
    exit;
} else {
    $file = fopen($old_name, “r”); //   打开文件
    //   输入文件标签
    Header(“Content-type:   application/octet-stream”);
    Header(“Accept-Ranges:   bytes”);
    Header(“Accept-Length:   “.filesize($old_name));
    Header(“Content-Disposition:   attachment;   filename=”.$file_name);
    //   输出文件内容
    echo fread($file, filesize($old_name));
    fclose($file);
    exit;
}
}

C#版如下:

public static void ToDownload(string serverfilpath,string filename)
{
    FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
    long fileSize = fileStream.Length;
    HttpContext.Current.Response.ContentType = “application/octet-stream”;
    HttpContext.Current.Response.AddHeader(“Content-Disposition”, “attachment; filename=\”” + UTF_FileName(filename) + “\”;”);
    ////attachment — 作为附件下载
    ////inline — 在线打开
    HttpContext.Current.Response.AddHeader(“Content-Length”, fileSize.ToString());
    byte[] fileBuffer = new byte[fileSize];
    fileStream.Read(fileBuffer, 0, (int)fileSize);
    HttpContext.Current.Response.BinaryWrite(fileBuffer);
    fileStream.Close();
    HttpContext.Current.Response.End();
}
public static void ToOpen(string serverfilpath, string filename)
{
    FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
    long fileSize = fileStream.Length;
    HttpContext.Current.Response.ContentType = “application/octet-stream”;
    HttpContext.Current.Response.AddHeader(“Content-Disposition”, “inline; filename=\”” + UTF_FileName(filename) + “\”;”);
    HttpContext.Current.Response.AddHeader(“Content-Length”, fileSize.ToString());
    byte[] fileBuffer = new byte[fileSize];
    fileStream.Read(fileBuffer, 0, (int)fileSize);
    HttpContext.Current.Response.BinaryWrite(fileBuffer);
    fileStream.Close();
    HttpContext.Current.Response.End();
}
private static string UTF_FileName(string filename)
{
    return HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8);
}

所以其实最后的C++版也就比较明显了(我没有读本地文件,因为内容直接在一个string的buff里):

printf(“Content-type:   application/octet-stream\r\n”);
printf(“Content-Length: %u\r\n”,ccpp.filecontent.size());
printf(“Content-Disposition:   attachment;   filename= %s\r\n\r\n”,filename.c_str());
const char *ptr = ccpp.filecontent.c_str();
for(unsigned int i =0 ;i < ccpp.filecontent.size();++i)
{
    putchar(*(ptr+i));
}

先解释一下,由于webserver会将标准输出重定向,所以用printf实际就是返回到了浏览器端,至于用putchar是因为二进制的原因。
在这里还碰到了一个诡异的问题,即用

write(1,ptr,ccpp.filename.size());

会直接500 error,不知道为什么……

在CGI中通过Etag和Cache-Control来控制流量,访问量及生效时间

最近遇到一个需求,即一个配置文件,由于这个文件的访问量非常大(8000次/秒),并且配置文件本身也比较大,所以需要 1.发布之后在5分钟之内生效 2.要...

阅读全文

QQ餐厅公测,入口CGI的一个bug定位

首先庆祝一下QQ餐厅正式不删档公测,本以为终于可以不用那么晚发版本了,结果昨晚入口CGI出现问题,折腾到凌成4点多,杯具…… 先截个餐厅的图给大家看一下: ...

阅读全文

在CGI中执行外部命令的方法

这几天在做的一个系统中,需要给指定的用户发送email,由于对方只提供了可执行程序,所以需要在CGI中调用。 虽然之前就知道可以通过system()或者popen()来...

阅读全文

3则回应给“CGI返回弹出下载文件对话框的HTML代码”

  1. gf说道:

    赞一个!!

    [回复]

发表评论