当前位置: 首页 > 工具软件 > GoAhead > 使用案例 >

goahead实现文件下载功能实例详解

林修真
2023-12-01

总体来说,goahead实现文件下载功能比较简单,基本上是调用固定的函数,但是也有一些坑,下面详细讲解我的实例记录。

(1)定义下载的回调函数

websDefineAction("downloadConfigFile", downloadConfigFile);

(2)下载回调函数的实现

static void downloadConfigFile(Webs *wp, char *path, char *query){

    WebsHandlerProc service = (*wp).route->handler->service;

    (*wp).route->handler->close = (*avolfileClose);

    (*wp).route->handler->service =(*ConfigfileHandler);

    (*wp).route->handler->service(wp);

    (*wp).route->handler->service= service;

}

上面函数的关键部分是ConfigfileHandler的实现,具体实现见(3)

(3)关键函数实现

关键点在下面函数的分割线处

static bool ConfigfileHandler(Webs *wp){

    WebsFileInfo    info;

    char *tmp, *date;

    ssize nchars;

    int code;

    char* pathfilename; //带路径的文件名 用于找到对应的文件

    char* filenameExt; //文件扩展名 用于 设置 MIME类型

    char* filename; //文件名 用于下载后保存的文件名称

    char* disposition; //临时保存 附件 标识

    char    *filebegin;

    char    *filend;

    char file_name_arr[50];

    assert(websValid(wp));

    assert(wp->method);

    assert(wp->filename && wp->filename[0]);

    // ******************************分割线******************************//

     //下面语句的websGetVar的第二个参数"filepath"与最后一步的具体的下载操作有关系

    pathfilename = websGetVar(wp, "filepath", NULL);

    if (pathfilename==NULL)

        return true;

    //取文件名和扩展名

    filebegin = strrchr(pathfilename,'/');

    filend = strchr(pathfilename,'.');

    memset(file_name_arr,0,50);

    snprintf(file_name_arr,strlen(filebegin) - strlen(filend) - 1,"%s",filebegin + 1);

    // strncpy(file_name_arr,filebegin + 1, strlen(filebegin) - strlen(filend) - 1);

    filename =sclone("config");

    filenameExt =sclone("tar.gz");

    if (wp->ext) wfree(wp->ext);

   

    wp->ext=(char*)walloc(1+strlen(filenameExt)+1);

    sprintf(wp->ext,".%s",sclone(filenameExt));

    if (wp->filename) {

        wfree(wp->filename);

    }

    wp->filename=sclone(pathfilename);

    if (wp->path) {

        wfree(wp->path);

    }

    wp->path=sclone(pathfilename);

        //If the file is a directory, redirect using the nominated default page

        if (websPageIsDirectory(wp)) {

            nchars = strlen(wp->path);

            if (wp->path[nchars - 1] == '/' || wp->path[nchars - 1] == '\\') {

                wp->path[--nchars] = '\0';

            }

        char* websIndex = "testdownload";

            tmp = sfmt("%s/%s", wp->path, websIndex);

            websRedirect(wp, tmp);

            wfree(tmp);

            return true;

        }

        if (websPageOpen(wp, O_RDONLY | O_BINARY, 0666) < 0) {

            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot open document for: %s", wp->path);

            return true;

        }

        if (websPageStat(wp, &info) < 0) {

            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot stat page for URL");

            return true;

        }

        code = 200;

        if (wp->since && info.mtime <= wp->since) {

            code = 304;

        }

        websSetStatus(wp, code);

        websWriteHeaders(wp, info.size, 0);

    //浏览器下载文件时的文件名

    disposition = (char*)walloc(20+strlen(filename)+ strlen(filenameExt)+1);

    sprintf(disposition,"attachment;filename=%s.%s",sclone(filename),sclone(filenameExt));

    websWriteHeader(wp, "Content-Disposition", sclone(disposition));

    free(filename);

    free(disposition);

    filename=NULL;

    disposition=NULL;

    free(filenameExt);

    filenameExt=NULL;

        if ((date = websGetDateString(&info)) != NULL) {

            websWriteHeader(wp, "Last-modified", "%s", date);

            wfree(date);

        }

        websWriteEndHeaders(wp);

        //All done if the browser did a HEAD request

        if (smatch(wp->method, "HEAD")) {

            websDone(wp);

            return true;

        }

        websSetBackgroundWriter(wp, fileWriteEvent);

    return true;

}

(4)其他函数实现

static void fileWriteEvent(Webs *wp)

{

    char    *buf;

    ssize   len, wrote;

    int     err;

    assert(wp);

    assert(websValid(wp));

    if ((buf = walloc(ME_GOAHEAD_LIMIT_BUFFER)) == NULL) {

        websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot get memory");

        return;

    }

    while ((len = websPageReadData(wp, buf, ME_GOAHEAD_LIMIT_BUFFER)) > 0) {

        if ((wrote = websWriteSocket(wp, buf, len)) < 0) {

            err = socketGetError(wp->sid);

            if (err == EWOULDBLOCK || err == EAGAIN) {

                websPageSeek(wp, -len, SEEK_CUR);

            } else {

                /* Will call websDone below */

                wp->state = WEBS_COMPLETE;

            }

            break;

        }

        if (wrote != len) {

            websPageSeek(wp, - (len - wrote), SEEK_CUR);

            break;

        }

    }

    wfree(buf);

    if (len <= 0) {

        websDone(wp);

    }

}

static bool avolfileHandler(Webs *wp){

    WebsFileInfo    info;

    char *tmp, *date;

    ssize nchars;

    int code;

    char* pathfilename; //带路径的文件名 用于找到对应的文件

    char* filenameExt; //文件扩展名 用于 设置 MIME类型

    char* filename; //文件名 用于下载后保存的文件名称

    char* disposition; //临时保存 附件 标识

   

    assert(websValid(wp));

    assert(wp->method);

    assert(wp->filename && wp->filename[0]);

    // 取download.lua?log=C:\aa.log 中的 C:\aa.log

    pathfilename = websGetVar(wp, "log", NULL);

    if (pathfilename==NULL)

        return true;

    //取文件名和扩展名

    filename =sclone("aa");

    filenameExt =sclone("log");

   

    if (wp->ext) wfree(wp->ext);

    wp->ext=(char*)walloc(1+strlen(filenameExt)+1);

    sprintf(wp->ext,".%s",sclone(filenameExt));


 

    if (wp->filename) {

        wfree(wp->filename);

    }

    wp->filename=sclone(pathfilename);

    if (wp->path) {

        wfree(wp->path);

    }

    wp->path=sclone(pathfilename);

   

        //If the file is a directory, redirect using the nominated default page

        if (websPageIsDirectory(wp)) {

            nchars = strlen(wp->path);

            if (wp->path[nchars - 1] == '/' || wp->path[nchars - 1] == '\\') {

                wp->path[--nchars] = '\0';

            }

        char* websIndex = "testdownload";

            tmp = sfmt("%s/%s", wp->path, websIndex);

            websRedirect(wp, tmp);

            wfree(tmp);

            return true;

        }

        if (websPageOpen(wp, O_RDONLY | O_BINARY, 0666) < 0) {

            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot open document for: %s", wp->path);

            return true;

        }

        if (websPageStat(wp, &info) < 0) {

            websError(wp, HTTP_CODE_NOT_FOUND, "Cannot stat page for URL");

            return true;

        }

        code = 200;

        if (wp->since && info.mtime <= wp->since) {

            code = 304;

        }

        websSetStatus(wp, code);

        websWriteHeaders(wp, info.size, 0);

    //浏览器下载文件时的文件名

    disposition = (char*)walloc(20+strlen(filename)+ strlen(filenameExt)+1);

    sprintf(disposition,"attachment;filename=%s.%s",sclone(filename),sclone(filenameExt));

    websWriteHeader(wp, "Content-Disposition", sclone(disposition));

    free(filename);

    free(disposition);

    filename=NULL;

    disposition=NULL;

    free(filenameExt);

    filenameExt=NULL;

        if ((date = websGetDateString(&info)) != NULL) {

            websWriteHeader(wp, "Last-modified", "%s", date);

            wfree(date);

        }

        websWriteEndHeaders(wp);

        //All done if the browser did a HEAD request

        if (smatch(wp->method, "HEAD")) {

            websDone(wp);

            return true;

        }

        websSetBackgroundWriter(wp, fileWriteEvent);

    return true;

}

(5)下载文件操作

在浏览器输入:http://10.10.10.10:8080/action?filepath=/tmp/111.jpg即可下载相应文件

对上述 输入内容的说明:http://10.10.10.10(具体服务器的IP):8080(端口号)/action(固定为action)/downloadConfigFile(对应于注册回调函数时的字符串)?filepath(对应于分割线处的函数入参)=/tmp/111.jpg(具体的文件路径)

(6)上述内容部分参考自:goahead下载文件 - 走看看 (zoukankan.com),致谢。欢迎同行相互讨论赐教。

 类似资料: