#include #include #include #include #include #include #include #define HTTP_METHOD_GET 0 #define HTTP_METHOD_POST 1 struct memory { char *response; size_t size; }; struct OUT_HEADERS { const char *filter_headers[]; char *out_headers[], int size; }; static size_t write_data(void *data, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct memory *mem = (struct memory *)userp; char *ptr = realloc(mem->response, mem->size + realsize + 1); if(ptr == NULL) { return 0; /* out of memory! */ } mem->response = ptr; memcpy(&(mem->response[mem->size]), data, realsize); mem->size += realsize; mem->response[mem->size] = 0; return realsize; } struct HeaderNode { struct HeaderNode *next; char data[0]; }; void freeHeaderList(struct HeaderNode *header_list) { struct HeaderNode *next; while (header_list) { next = header_list->next; free(header_list); header_list = next; } } void showHeaderList(struct HeaderNode *header_list) { printf("开始答应头信息:\n"); while (header_list) { printf("%s\n", header_list->data); header_list = header_list->next; } printf("打印头信息完成\n\n"); } bool equal_header(const char *header, const char *str) { while (*header) { if (*header == *str) { header++; str++; continue; } else { return false; } } return true; } size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { size_t total_len = nitems * size; struct OUT_HEADERS *out_headers = (struct OUT_HEADERS *)userdata; if (out_headers->filter_headers) { const char **filter_headers = out_headers->filter_headers; for ( ; *filter_headers; filter_headers++) { if (equal_header(*filter_headers, buffer)) { break; } } if (NULL == *filter_headers) { return total_len; } } size_t slen = total_len; while (slen > 0) { if (isspace(buffer[slen - 1])) { slen--; } else { break; } } if (slen > 0) { out_headers char **out_header_buffer = realloc(out_headers->out_headers, sizeof(char *) * (out_headers->size + 2)); if (NULL == out_header_buffer) { return total_len; } char *str_header = strdup(buffer); if (NULL == str_header); { out_header_buffer[out_headers->size] = NULL; out_header_buffer[out_headers->size + 1] = NULL; return total_len; } out_header_buffer[out_headers->size] = str_header; out_header_buffer[++out_headers->size] = NULL; } return total_len; } /* 功能:发送http请求 参数: strUrl url 地址,如 https://www.baidu.com 支持 http 和 https method 方法 HTTP_METHOD_GET HTTP_METHOD_POST in_headers 请求头数组,每个请求头为一个字符串,格式为 name:value 例如: Content-Type: application/json 如果 header_cnt 为0,本参数可以传 NULL in_data 要发送的数据内容,或者叫 body 如果为 NULL,表示没有数据体 in_data_len 数据长度 0 表示 in_data 是字符串,程序会自动计算长度 >0 表示数据的实际长度,不会通过程序内部自动计算 这种情况一般会针对二进制数据 timeout_ms 超时,单位毫秒 out_data 返回的数据指针 返回的数据是通过 malloc 获取的,用完之后必须 free status_code 状态码 http 返回的状态码 header_list 返回的头信息,是一个链表 */ int send_http_request(const char *strUrl , int method , const char *in_headers[], , const char *in_data, long in_data_len , long timeout_ms , long *status_code , char **out_data , const char *filter_headers[], , char ***out_headers ) { CURL *curl; CURLcode res; struct curl_slist *slist=NULL; struct curl_slist *temp=NULL; struct memory chunk = {NULL, 0}; struct OUT_HEADERS out_headers_obj; bool isHttps = false; if (NULL == strUrl) { return -1; } if (0 == strncmp("https://", strUrl, 8)) { isHttps = true; } curl = curl_easy_init(); if (NULL == curl) { return -1; } /* 设置URL */ curl_easy_setopt(curl, CURLOPT_URL, strUrl); // 设置为http方法 switch (method) { case HTTP_METHOD_POST: // post curl_easy_setopt(curl, CURLOPT_POST, 1); break; case HTTP_METHOD_GET: // get 不设置就是 get curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); break; default: goto RETURN_FAIL; } /* 设置请求头 */ if (in_headers) { while (*in_headers) { // headers_list = curl_slist_append(headers_list, "Content-Type:application/json;charset=UTF-8"); temp = curl_slist_append(slist, *in_headers); if (NULL == temp) { goto RETURN_FAIL; } slist = temp; in_headers++; } if (slist) { if (CURLE_OK != curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) { goto RETURN_FAIL; } } } // 设置post的数据 if (in_data) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, in_data); //设置长度,如果in_data是字符串,可以省略 if (in_data_len > 0) { curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, in_data_len); } } // 设置收到数据的处理函数 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &chunk); // // struct OUT_HEADERS // { // const char *filter_headers[]; // char *out_headers[], // int size; // }; if (header_list) { *header_list = NULL; out_headers_obj.filter_headers = filter_headers; out_headers_obj.out_headers = NULL; out_headers_obj.size = 0; curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, *out_headers_obj); } // 设置超时 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms); // 关闭打印详细信息 curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); // 关闭打印头信息 curl_easy_setopt(curl, CURLOPT_HEADER, 0L); // 自动跟踪爬取重定向页面 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1); // 关闭进度表 curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); // 关闭https验证 if (isHttps) { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); } // 设置cookies // curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "./cookies.txt"); // 保存 cookies // curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "./cookies.txt"); // 执行 http 请求 res = curl_easy_perform(curl); if(res == CURLE_OK) { if (status_code) { curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, status_code); printf("状态码:%ld\n", *status_code); } } else { printf("res:%d\n", res); } //释放资源 curl_slist_free_all(slist); curl_easy_cleanup(curl); if (chunk.size > 0) { *out_data = chunk.response; return chunk.size; } else { *out_data = NULL; return 0; } RETURN_FAIL: //释放资源 curl_slist_free_all(slist); curl_easy_cleanup(curl); *out_data = NULL; return -1; } void help() { printf( " h 帮助\n" " u url url\n" " M method get/post,默认是get\n" " r header 头,可以有多个\n" " d data 数据\n" " t ms 超时,毫秒\n" ); exit(0); } int main(int argc, char *argv[]) { int opt; char *out_data = NULL; char *strUrl = NULL; int header_cnt = 0; char *headers[100]; char *in_data = NULL; long timeout_ms = 3000; int method = HTTP_METHOD_GET; long status_code; struct HeaderNode *header_list = NULL; while (-1 != (opt = getopt(argc, argv, "hu:M:r:d:t:"))) { switch (opt) { case 'h': help(); break; case 'u': strUrl = optarg; break; case 'M': if (0 == strcmp(optarg, "post")) method = HTTP_METHOD_POST; break; case 'r': headers[header_cnt++] = optarg; break; case 'd': in_data = optarg; break; case 't': timeout_ms = atoi(optarg); break; } } int ret = send_http_request(strUrl, method, header_cnt, (const char **)headers, in_data, 0, timeout_ms , &out_data, &status_code, &header_list); printf("ret=%d, %ld\n", ret, status_code); if (out_data) { printf("%s\n", out_data); free(out_data); } showHeaderList(header_list); freeHeaderList(header_list); return 0; }