需要三个文件,目录结构如下图:

httpclient.c 实现POST请求的封装
httpclient.h 用于对外提供接口
test.c 是测试文件,测试POST能否发送请求。
httpclient.c文件,封装libcurl的POST请求接口,实现POST发送,并获取content数据。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include "httpclient.h"
/*
* post请求的返回结果回调函数
* 把content的数据copy到userdata给定的空间
* 注意:需要在外部释放申请的 userdata.data 空间
*/
size_t post_callback(void* contents, size_t size, size_t nmemb, void* userdata) {
// 判断contents是否返回了空值
if (contents == NULL) {
return 0;
}
// 一次回调返回的数据量
size_t realsize = size * nmemb;
if (userdata == NULL) {
return realsize ;
}
// 类型转换
http_resp_data * resp_data = (http_resp_data *) userdata;
resp_data->data= (char*)calloc(1, realsize );
if (resp_data->data== NULL) {
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(resp_data->data, contents, realsize);
resp_data->size = realsize;
return realsize; //必须返回真实的数据
}
#define MAX_URL_LEN 256
/*
* 示例 :
* proto : http or https
* host : 127.0.0.1:8080 host:port
* method : /xxx/yyy
* data : {"aa":"aaaaaaaaaaa","bb","bbbbbbbbbbbbbbbb", .... }
* size : data的字节数
* user_data : 回调函数待处理的数据
*/
int http_post_by_json(const char * proto, const char* host, const char* method, const char* data, size_t size, http_resp_data* user_data) {
int ret = 0;
// 1、初始化
CURL* curl = curl_easy_init();
if (curl == NULL) {
printf("curl easy init");
ret = -1;
goto over;
}
// 2、拼写完整的URL
char new_url[MAX_URL_LEN] = {0} ;
if (method[0] == '/') {
sprintf(new_url, "%s://%s%s", proto, host, method );
} else {
sprintf(new_url, "%s://%s/%s", proto, host, method);
}
// 3、设置参数
// 3.1、设置使用POST方法(默认使用GET方法发送请求),
curl_easy_setopt(curl, CURLOPT_POST, 1);
// 返回完整的HTTP响应头
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
// 3.2、header.Content-Type 和 header.Accept 信息
struct curl_slist* headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json") ;
headers = curl_slist_append(headers, "Accept: */*") ;
// 3.3、设置 header.Host
char host_header[MAX_URL_LEN] = {0};
sprintf(host_header, "Host: %s", host);
headers = curl_slist_append(headers, host_header);
// 3.4、设置header和body
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, size);
// 3.5、设置请求超时时间
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5);
// 3.6、设置回调函数
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, post_callback);
// 3.7、允许重定向地址
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1) ;
// 3.8、设置url地址
curl_easy_setopt(curl, CURLOPT_URL, new_url);
// 3.9、设置向回调函数传递的数据
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)user_data);
// 4、发起请求
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
const char* error = curl_easy_strerror(res);
printf("http post request failure, url=%s curl code=%d error=%s", new_url, res, error);
ret = -1;
goto over;
}
// 5、判断返回码
long http_code = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code >= 400) {
printf("http post request failure, url=%s curl code=%ld", new_url, http_code) ;
ret = -1;
goto over;
} else {
printf("success http_code=%ld\n", http_code) ;
}
over :
curl_easy_cleanup(curl);
return ret;
}
httpclient.h文件,上方代码对应的头文件,用于对外暴露接口。
#ifndef __HTTP_CLIENT_H__
#define __HTTP_CLIENT_H__
#include <stdio.h>
typedef struct http_resp_data_t {
char * data;
size_t size;
} http_resp_data;
/*
* 示例 :
* proto : http or https
* host : 127.0.0.1:8080 host:port
* method : /xxx/yyy
* data : {"aa":"aaaaaaaaaaa","bb","bbbbbbbbbbbbbbbb", .... }
* size : data的字节数
* user_data : 回调函数待处理的数据
*/
int http_post_by_json(const char * proto, const char* host, const char* method, const char* data, size_t size, http_resp_data* user_data) ;
#endif
调用程序test.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "httpclient.h"
int main() {
http_resp_data resp_data ;
memset(&resp_data, 0x00, sizeof(http_resp_data)) ;
char * data = "{\"name\":\"madbull.site\", \"tel\":\"12312312311\", \"email\":\"aaa@ccc.com\"}" ;
http_post_by_json("http", "127.0.0.1:3322", "/test/t1", data, strlen(data), &resp_data) ;
if(resp_data.data != NULL) {
printf("resp_data.data [%s]\n", resp_data.data) ;
free(resp_data.data) ;
memset(&resp_data, 0x00, sizeof(http_resp_data)) ;
}
return 0 ;
}
本次测试用来 之前使用go搭建的 POST请求,可以翻看 https://www.madbull.site/?p=749 搭建起http服务器。服务正常启动后,可按照下边的方法编译和测试:

发表回复