近期在开发一个小项目时候需要用到发送HTTP的请求,这个用Python很容易实现,不过这次代码环境是C++,所以就想用C++写一个发送HTTP请求的代码。
需求:需要在一个Post请求中,发送到HTTP服务端几个参数,同时要发送一批图片。
在一番调研之后发现用libcurl库可以实现需求,但是在写代码的过程中遇到了一些对curl_formadd API理解的问题,特此写出来以供分享。
附上libcurl API的官网:https://curl.haxx.se/libcurl/c/curl_formadd.html
libcurl的主要用法主要包括以下三点:
1、curl全局初始化
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
2、curl easy初始化
CURL* easy_handler = curl_easy_init();
3、curl 属性的设置
【以下的例子表示的是设置要发送的URL地址】
curl_easy_setopt(easy_handler,CURLOPT_URL,"http://127.0.0.1:8090/detection");
【以下的例子表示的是设置要发送参数,key=“AI_ID”,value="12"】
curl_httppost* post = NULL;
curl_httppost* last = NULL;
使用该方法需要设置两个指针,分别是起始和结束指针。
curl_formadd(&post,&last,CURLFORM_COPYNAME,"AI_ID",CURLFORM_COPYCONTENTS,"12",CURLFORM_END);
4、设置发送方法post
curl_easy_setopt(easy_handler, CURLOPT_HTTPPOST, post);
此处的post是在 curl_formadd中的第一个参数。是一个curl_httppost*
5、执行发送
code = curl_easy_perform(easy_handler);
6、资源释放
curl_formfree(post); 【用来释放curl_formadd添加的数据】
curl_easy_cleanup(easy_handler); 【用来释放easy 句柄资源】
curl_global_cleanup(); 【用来释放全局资源】
==============================================================================================
但是,在使用过程中出现了一些错误,对http post的发送域没理解对。
我们先看官网翻译之后的内容:
struct curl_httppost * post = NULL;
struct curl_httppost * last = NULL;
char namebuffer [] =“名称缓冲区”;
long namelength = strlen(namebuffer);
char buffer [] =“test buffer”;
char htmlbuffer [] =“<HTML> test buffer </ HTML>”;
long htmlbufferlength = strlen(htmlbuffer);
struct curl_forms forms[3];
char file1 [] =“my-face.jpg”;
char file2 [] =“your-face.jpg”;
/ *将空字符添加到htmlbuffer中,以证明
包含空字符的缓冲区的传输实际上有效
* /
htmlbuffer [8] ='\ 0';
/ *添加简单的名称/内容部分* /
curl_formadd(&post,&last,
CURLFORM_COPYCONTENTS,“content”,CURLFORM_END);
/ *添加简单名称/内容/ contenttype部分* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“htmlcode”,
CURLFORM_COPYCONTENTS,“<HTML> </ HTML>”,
CURLFORM_CONTENTTYPE,“text / html”,CURLFORM_END);
/ *添加名称/ ptrcontent部分* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“name_for_ptrcontent”,
CURLFORM_PTRCONTENTS,buffer,CURLFORM_END);
/ *添加ptrname / ptrcontent section * /
curl_formadd(&post,&last,CURLFORM_PTRNAME,namebuffer,
CURLFORM_PTRCONTENTS,buffer,CURLFORM_NAMELENGTH,
namelength,
/ *添加名称/ ptrcontent / contenttype section * /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“html_code_with_hole”,
CURLFORM_PTRCONTENTS,htmlbuffer,
CURLFORM_CONTENTSLENGTH,htmlbufferlength,
CURLFORM_CONTENTTYPE,“text / html”,CURLFORM_END);
/ *添加简单文件部分* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“picture”,
CURLFORM_FILE,“my-face.jpg”,CURLFORM_END);
/ *添加文件/ contenttype部分* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“picture”,
CURLFORM_FILE,“my-face.jpg”,
CURLFORM_CONTENTTYPE,“image / jpeg”,CURLFORM_END);
/ *添加两个文件部分* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“pictures”,
CURLFORM_FILE,“my-face.jpg”,
CURLFORM_FILE,“your-face.jpg”,CURLFORM_END);
/ *使用CURLFORM_ARRAY * /
forms [0] .option = CURLFORM_FILE 添加两个文件部分;
forms [0] .value = file1;
forms [1] .option = CURLFORM_FILE;
forms [1] .value = file2;
forms [2] .option = CURLFORM_END;
/ *添加缓冲区以上传* /
curl_formadd(&post,&last,
CURLFORM_COPYNAME,“name”,
CURLFORM_BUFFER,“data”,
CURLFORM_BUFFERPTR,record,
CURLFORM_BUFFERLENGTH,record_length,
/ *结束标记* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“pictures”,
CURLFORM_ARRAY,forms,CURLFORM_END)不需要选项;
/ *将文件内容添加为正常的文本后值* /
curl_formadd(&post,&last,CURLFORM_COPYNAME,“filecontent”,
CURLFORM_FILECONTENT,“。bashrc”,CURLFORM_END);
/ *设置表单info * /
curl_easy_setopt(curl,CURLOPT_HTTPPOST,post);
其中,添加两个文件的用法经测试是不能用的。
当我们如果使用了 curl_easy_setopt的时时候就需要如下所示将所有参数传过去,服务端会根据&自动进行分割,从而获取到所需要的参数值。
curl_easy_setopt(easy_handler,CURLOPT_POSTFIELDS,"ID=1&AI_ID=2&gift_url=123")
但是,如果想使用curl_formadd,则需要明白其关键字的用法,且在设置属性的时候不能混用curl_easy_setopt和curl_formadd,只能选择一个来使用。
具体请见官网,以下只写几个常用的关键字
CURLFORM_COPYNAME:在curl_formadd中,该参数后面跟的字符串是key的名字,CURLFORM_COPYCONTENTS:后面跟的字符串为key的值,可以用这种方式设置多个key。
CURLFORM_COPYNAME:在curl_formadd中,该参数同样跟的是key,不过如果想发送文件,则采用关键CURLFORM_FILE,这样可以表示key所对应的文件,设置多个文件,其key相同,就能发送多个文件了。
以下是本人写的一些例子:代码亲测可用
#include <iostream>
#include <string>
using namespace std;
extern "C" {
#include <curl/curl.h>
}
size_t process_data(void* buffer,size_t size,size_t nmemb,void* user_p){
FILE *fp = (FILE*)user_p;
size_t return_size = fwrite(buffer,size,nmemb,fp);
cout<<(char*)buffer<<endl;
}
int get(void){
CURLcode return_code;
return_code = curl_global_init(CURL_GLOBAL_ALL);
if(return_code != CURLE_OK){
cerr<<"curl_global_init failed!"<<endl;
return -1;
}
//get easyhandle
CURL* easy_handler = curl_easy_init();
if(easy_handler == NULL){
cerr<<"curl_easy_init failed!"<<endl;
curl_global_cleanup();
return -1;
}
FILE* fp = fopen("data.html","ab+");
//set easy opt
curl_easy_setopt(easy_handler,CURLOPT_URL,"http://blog.csdn.net/JGood");
curl_easy_setopt(easy_handler,CURLOPT_WRITEFUNCTION,&process_data);
curl_easy_setopt(easy_handler,CURLOPT_WRITEDATA,fp);
//exe
curl_easy_perform(easy_handler);
fclose(fp);
curl_easy_cleanup(easy_handler);
curl_global_cleanup();
return 0;
}
size_t read_data(void* buffer,size_t size,size_t nmemb,void* user_p){
FILE* fp = (FILE *)user_p;
return fread(buffer,size,nmemb,fp);
}
int post(void){
CURLcode code;
code = curl_global_init(CURL_GLOBAL_ALL);
if (code != CURLE_OK){
cerr<<"curl global init failed!"<<endl;
return -1;
}
FILE *fp = fopen("data.html","rb");
if(NULL == fp){
cerr<<"fopen failed!"<<endl;
curl_global_cleanup();
return -1;
}
fseek(fp,0,2);
int file_size = ftell(fp);
rewind(fp);
//get easy handler
CURL *easy_handler = curl_easy_init();
if(easy_handler == NULL){
cerr<<"curl easy init failed!"<<endl;
fclose(fp);
curl_global_cleanup();
return -1;
}
curl_easy_setopt(easy_handler,CURLOPT_URL,"http://localhost:8090/detection");
curl_easy_setopt(easy_handler,CURLOPT_UPLOAD,1);
curl_easy_setopt(easy_handler,CURLOPT_READFUNCTION,&read_data);
curl_easy_setopt(easy_handler,CURLOPT_READDATA,fp);
curl_easy_setopt(easy_handler,CURLOPT_INFILESIZE_LARGE,file_size);
//
code = curl_easy_perform(easy_handler);
if(code == CURLE_OK){
cout<<"upload success"<<endl;
}
fclose(fp);
curl_easy_cleanup(easy_handler);
curl_global_cleanup();
return 0;
}
int post_arguments(void){
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
CURL* easy_handler = curl_easy_init();
curl_easy_setopt(easy_handler,CURLOPT_URL,"http://localhost:8090/detection");
curl_easy_setopt(easy_handler,CURLOPT_POSTFIELDS,"ID=1&AI_ID=2&gift_url=123");
code = curl_easy_perform(easy_handler);
if(code == CURLE_OK){
cout<<"post arguments success"<<endl;
}
curl_easy_cleanup(easy_handler);
curl_global_cleanup();
return 0;
}
int post_multi_part(void){
CURLcode code;
code = curl_global_init(CURL_GLOBAL_ALL);
if(code != CURLE_OK){
cerr<<"curl global init failed!"<<endl;
curl_global_cleanup();
return -1;
}
CURL* easy_handler = curl_easy_init();
if(easy_handler == NULL){
cerr<<"curl easy init failed!"<<endl;
curl_global_cleanup();
return -1;
}
curl_easy_setopt(easy_handler,CURLOPT_URL,"http://localhost:8090/detection");
//curl_easy_setopt(easy_handler,CURLOPT_POSTFIELDS,"ID=1&AI_ID=2&gift_url=123");
curl_httppost* post = NULL;
curl_httppost* last = NULL;
string ID = "123";
string AI_ID = "1234567";
string gift_url = "sdfsdfdsfdsf";
curl_formadd(&post,&last,CURLFORM_COPYNAME,"AI_ID",CURLFORM_COPYCONTENTS,AI_ID.c_str(),CURLFORM_END);
curl_formadd(&post,&last,CURLFORM_COPYNAME,"ID",CURLFORM_COPYCONTENTS,ID.c_str(),CURLFORM_END);
curl_formadd(&post,&last,CURLFORM_COPYNAME,"gift_url",CURLFORM_COPYCONTENTS,gift_url.c_str(),CURLFORM_END);
curl_formadd(&post,&last,CURLFORM_COPYNAME,"newImg",CURLFORM_FILE,"./picture_1.png",CURLFORM_END);
curl_formadd(&post,&last,CURLFORM_COPYNAME,"newImg",CURLFORM_FILE,"./picture_2.png",CURLFORM_END);
curl_formadd(&post,&last,CURLFORM_COPYNAME,"newImg",CURLFORM_FILE,"./picture_3.png",CURLFORM_END);
char buffer[1024];
snprintf(buffer,sizeof(buffer),"%d",123);
cout<<buffer<<endl;
/*
char file1[] = "./picture_1.png";
char file2[] = "./picture_2.png";
struct curl_forms arr[3];
arr[0].option = CURLFORM_FILE;
arr[0].value = file1;
arr[1].option = CURLFORM_FILE;
arr[1].value = file2;
arr[2].option = CURLFORM_END;
curl_formadd(&post,&last,CURLFORM_COPYNAME,"newImg",CURLFORM_ARRAY,arr,CURLFORM_END);
*/
curl_easy_setopt(easy_handler,CURLOPT_HTTPPOST,post);
code = curl_easy_perform(easy_handler);
if(code != CURLE_OK){
cerr<<"curl easy perform failed!"<<endl;
curl_easy_cleanup(easy_handler);
curl_global_cleanup();
return -1;
}
curl_formfree(post);
curl_easy_cleanup(easy_handler);
curl_global_cleanup();
return 0;
}
int main(void){
//get();
//post_arguments();
post_multi_part();
return 0;
}