日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

C/C++:mongoose.c实现多表单域文件上传

發(fā)布時(shí)間:2025/3/15 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C/C++:mongoose.c实现多表单域文件上传 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

筆者這里有需求需要用mongoose.c在上傳文件的時(shí)候同時(shí)還要提交其他表單字段,百度一圈居然沒(méi)有一個(gè)完整的例子,都是把源碼示例的上傳文件例子抄,講也沒(méi)講明白。源碼示例都是只有1個(gè)文件域上傳。由于mongoose.c 比較輕量級(jí),許多api也是在不斷更新。為了避免大家浪費(fèi)時(shí)間,先聲明筆者這里用的mongoose.c 的 6.13版本,版本在mongoose.h MG_VERSION宏中有聲明版本。這里筆者也把示例代碼拿來(lái)改造做1個(gè)多input項(xiàng)的文件上傳示例 做個(gè)拋磚引玉,當(dāng)然也會(huì)給大家講得明明白白,有圖有真相。

講解

需求

這里筆者只處理2個(gè)input項(xiàng),第1個(gè)input項(xiàng) path 指定服務(wù)器 將上傳的文件存儲(chǔ)在指定路徑下,第2個(gè)為 input file。

<input name="path" type="text" value="d:\\1.txt"/> <input name="file" type="file" />

多個(gè)文件input項(xiàng)以及多個(gè)普通input 道理都一樣,讀者可以看完 可以舉一反三的。

第1步 注冊(cè)處理文件上傳的http接口

/*上傳文件接口注冊(cè)參數(shù)1:mg_connection*參數(shù)2:uri,這里是/upload參數(shù)3:處理該請(qǐng)求的回調(diào)函數(shù),當(dāng)/upload這個(gè)uri請(qǐng)求到來(lái),就會(huì)走h(yuǎn)andle_upload這個(gè)回調(diào)函數(shù)。參數(shù)4:可選參數(shù),MG_UD_ARG是可以傳指定參數(shù)的 需要在mongoose.h中開(kāi)啟 MG_ENABLE_CALLBACK_USERDATA 宏。最后一個(gè)參數(shù)有啥用呢?比如我們有多個(gè)不同業(yè)務(wù)需求(多個(gè)不同的uri)的表單form-data(一般只用在文件上傳中)形式傳輸數(shù)據(jù)的,可以將代碼抽象出來(lái) 所有上傳接口都用1套代碼,將可變的數(shù)據(jù)都放到最后1個(gè)參數(shù)指針中(比如 傳輸完畢后的回調(diào)函數(shù)、不同uri上傳文件存儲(chǔ)位置等)如果只是單純的業(yè)務(wù)數(shù)據(jù)直接ajax發(fā)post請(qǐng)求即可,此種mongoose server可以參考示例restful_server。筆者這里只是拋轉(zhuǎn)引玉,這里代碼就不展開(kāi)了。*/ mg_register_http_endpoint(c, "/upload", handle_upload MG_UD_ARG(NULL));

第2步 編寫(xiě)處理文件上傳的回調(diào)函數(shù)

/*一次form-data表單數(shù)據(jù)請(qǐng)求,該函數(shù)會(huì)被回調(diào)多次。具體參數(shù)含義如下: 參數(shù)1:mg_connection* 參數(shù)2:這里的ev參數(shù),有下面5種情況,決定此次回調(diào)函數(shù)的功能,具體情況如下。MG_EV_HTTP_MULTIPART_REQUEST // 表單請(qǐng)求開(kāi)始,1次表單提交請(qǐng)求會(huì)有1次,可以獲取請(qǐng)求頭相關(guān)數(shù)據(jù)。MG_EV_HTTP_PART_BEGIN // 1個(gè)表單input項(xiàng)數(shù)據(jù)傳輸開(kāi)始,可以取到input name的值,回調(diào)n次(多少個(gè)input項(xiàng)回調(diào)多少次) MG_EV_HTTP_PART_DATA // 1個(gè)表單input項(xiàng)數(shù)據(jù)傳輸中,可以取到input value的值,如果是文件則為文件流,回調(diào)n*m次 MG_EV_HTTP_PART_END // 1個(gè)表單input項(xiàng)數(shù)據(jù)結(jié)束,回調(diào)n次(多少個(gè)input項(xiàng)回調(diào)多少次) MG_EV_HTTP_MULTIPART_REQUEST_END // 表單請(qǐng)求結(jié)束(也就是整個(gè)表單數(shù)據(jù)傳輸完畢),也是1次。// 可以進(jìn)行數(shù)據(jù)響應(yīng)操作,當(dāng)然如果只是一個(gè)input file項(xiàng),也可在MG_EV_HTTP_PART_END做數(shù)據(jù)響應(yīng)操作。 參數(shù)3:回調(diào)函數(shù)攜帶的數(shù)據(jù),與參數(shù)2有關(guān)聯(lián)。 參數(shù)4:可以是mg_register_http_endpoint綁定的第4個(gè)參數(shù),同時(shí)也是nc->user_data。這里筆者只處理2個(gè)input項(xiàng) <input name="path" type="text" value="d:\\1.txt"/> <input name="file" type="file" /> */ static void handle_upload(struct mg_connection *nc, int ev, void *p MG_UD_ARG(user_data))

代碼

需要注意的是,需要在mongoose.h中打開(kāi)http form-data文件上傳功能,宏定義如下:

#define MG_ENABLE_HTTP_STREAMING_MULTIPART 1 // 開(kāi)啟http form-data表單上傳文件

核心代碼如下。完整工程可以點(diǎn)這里進(jìn)行下載。

// 自定文件上傳item,這里不做復(fù)雜了 struct MyUploadItem{struct file_writer_data fileData;// 存放文件路徑char path[MAX_PATH];// 原始文件名char fileName[MAX_PATH]; }; /*一次form-data表單數(shù)據(jù)請(qǐng)求,該函數(shù)會(huì)被回調(diào)多次。具體參數(shù)含義如下: 參數(shù)1:mg_connection* 參數(shù)2:這里的ev參數(shù),有下面5種情況,決定此次回調(diào)函數(shù)的功能,具體情況如下。MG_EV_HTTP_MULTIPART_REQUEST // 表單請(qǐng)求開(kāi)始,1次表單提交請(qǐng)求會(huì)有1次,可以獲取請(qǐng)求頭相關(guān)數(shù)據(jù)。MG_EV_HTTP_PART_BEGIN // 1個(gè)表單input項(xiàng)數(shù)據(jù)傳輸開(kāi)始,可以取到input name的值,回調(diào)n次(多少個(gè)input項(xiàng)回調(diào)多少次) MG_EV_HTTP_PART_DATA // 1個(gè)表單input項(xiàng)數(shù)據(jù)傳輸中,可以取到input value的值,如果是文件則為文件流,回調(diào)n*m次 MG_EV_HTTP_PART_END // 1個(gè)表單input項(xiàng)數(shù)據(jù)結(jié)束,回調(diào)n次(多少個(gè)input項(xiàng)回調(diào)多少次) MG_EV_HTTP_MULTIPART_REQUEST_END // 表單請(qǐng)求結(jié)束(也就是整個(gè)表單數(shù)據(jù)傳輸完畢),也是1次。// 可以進(jìn)行數(shù)據(jù)響應(yīng)操作,當(dāng)然如果只是一個(gè)input file項(xiàng),也可在MG_EV_HTTP_PART_END做數(shù)據(jù)響應(yīng)操作。 參數(shù)3:回調(diào)函數(shù)攜帶的數(shù)據(jù),與參數(shù)2有關(guān)聯(lián)。 參數(shù)4:可以是mg_register_http_endpoint綁定的第4個(gè)參數(shù),同時(shí)也是nc->user_data。這里筆者只處理2個(gè)input項(xiàng) <input name="path" type="text" value="d:\\1.txt"/> <input name="file" type="file" /> */ static void handle_upload(struct mg_connection *nc, int ev, void *p MG_UD_ARG(user_data)) {// nc攜帶的自定義數(shù)據(jù)struct MyUploadItem *upData = (struct MyUploadItem *) nc->user_data;// MG_EV_HTTP_MULTIPART_REQUEST 事件回調(diào)時(shí),參數(shù)p為http_message*struct http_message* hm = (struct http_message*)p;// MG_EV_HTTP_PART_BEGIN、MG_EV_HTTP_PART_DATA、MG_EV_HTTP_PART_END 事件回調(diào)時(shí),參數(shù)p為mg_http_multipart_part*struct mg_http_multipart_part *mp = (struct mg_http_multipart_part *) p;char pTemp[128] = {0};switch (ev) {case MG_EV_HTTP_MULTIPART_REQUEST: {struct mg_str* mgTemp;printf("======form-data Begin=======================\n");// 在該EV中 可獲取請(qǐng)求頭中的數(shù)據(jù)printf("======Request Head Data begin======\n");mgTemp = mg_get_http_header(hm, "Content-Length");memcpy(pTemp, mgTemp->p, mgTemp->len);printf("Content-Length:%s \n", pTemp);mgTemp = mg_get_http_header(hm, "Content-Type");memset(pTemp, 0, 128);memcpy((void*)pTemp, (void*)mgTemp->p, mgTemp->len);printf("Content-Type:%s \n", pTemp);printf("======Request Head Data end========\n");if(upData == NULL){upData = (struct MyUploadItem*)calloc(1, sizeof(struct MyUploadItem));// 這里這樣賦值后,在下次回調(diào)upload_handle函數(shù)時(shí),第4個(gè)參數(shù)就用上了nc->user_data = (void *) upData;}break;}case MG_EV_HTTP_PART_BEGIN: {printf("======one input begin======\n");// 在該EV中 可以獲取input name 以及 filename,filename不為空時(shí)就為input fileif( mp->file_name != NULL && strlen(mp->file_name) > 0){// 該input項(xiàng)為 input file. 此時(shí)就可以打開(kāi)文件了,在MG_EV_HTTP_PART_DATA中就可以直接寫(xiě)數(shù)據(jù)了printf("input name:%s filename:%s\n", mp->var_name, mp->file_name);strcpy(upData->fileName, mp->file_name);upData->fileData.fp = fopen(upData->path, "wb+");;upData->fileData.bytes_written = 0;if (upData->fileData.fp == NULL) {mg_printf(nc, "%s","HTTP/1.1 500 Failed to open a file\r\n""Content-Length: 0\r\n\r\n");nc->flags |= MG_F_SEND_AND_CLOSE;return;}}else{// 普通input項(xiàng) printf("input name:%s \n", mp->var_name);}break;}case MG_EV_HTTP_PART_DATA: {if( mp->file_name != NULL && strlen(mp->file_name) > 0){// input fileif (fwrite(mp->data.p, 1, mp->data.len, upData->fileData.fp) != mp->data.len) {mg_printf(nc, "%s","HTTP/1.1 500 Failed to write to a file\r\n""Content-Length: 0\r\n\r\n");nc->flags |= MG_F_SEND_AND_CLOSE;return;}upData->fileData.bytes_written += mp->data.len;printf("input name:%s filename:%s writeLen:%d \n", mp->var_name, mp->file_name, upData->fileData.bytes_written);}else if(strcmp(mp->var_name, "path") == 0){memcpy(pTemp, mp->data.p, mp->data.len );// 普通input項(xiàng) printf("input name:%s value:%s \n", mp->var_name, pTemp);strcpy(upData->path, pTemp);}break;}case MG_EV_HTTP_PART_END: {printf("======one input end======\n");break;}case MG_EV_HTTP_MULTIPART_REQUEST_END: {printf("======form-data End=======================\n\n");mg_printf(nc,"HTTP/1.1 200 OK\r\n""Content-Type: text/plain\r\n""Connection: close\r\n\r\n""%s[len=%d] to %s success.\n\n",upData->fileName, (long) ftell(upData->fileData.fp), upData->path);nc->flags |= MG_F_SEND_AND_CLOSE;// 關(guān)閉文件fclose(upData->fileData.fp);// 釋放calloc分配的內(nèi)存free(upData);nc->user_data = NULL;break;}} }

測(cè)試結(jié)果

普通表單上傳測(cè)試

postman測(cè)試

mongoose 服務(wù)器打印日志

新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!

總結(jié)

以上是生活随笔為你收集整理的C/C++:mongoose.c实现多表单域文件上传的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。