关于libcurl的相关函数介绍以及参数详见官方说明 https://curl.haxx.se/libcurl/c/example.html
HTTP Request
一个http请求包含方法、路径、http版本、请求包头
请求方法 GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS
GET
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com?id=1")
POST
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "username=admin&password=123");
PUT
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
DELETE
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/file.txt");
libcurl HTTP 请求包头
默认不设置的包头
GET
GET /file1.txt HTTP/1.1
Host: localhost
Accept: */*
POST
POST /file1.txt HTTP/1.1
Host: localhost
Accept: */*
Content-Length: 6
Content-Type: application/x-www-form-urlencoded
设置自定义包头
添加一个包头 Name:Mike
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Name: Mike");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);
curl_slist_free_all(list); /* free the list again */
修改一个包头 Host: Alternative
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Host: Alternative");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);
curl_slist_free_all(list); /* free the list again */
删除一个包头
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Accept:");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);
curl_slist_free_all(list); /* free the list again */
提供一个没有内容的包头
struct curl_slist *list = NULL;
list = curl_slist_append(list, "Moo;");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
curl_easy_perform(curl);
curl_slist_free_all(list); /* free the list again */
HTTP Response
HTTP response code
常见HTTP响应码
Code Meaning
1xx Transient code, a new one follows
2xx Things are OK
3xx The content is somewhere else
4xx Failed because of a client problem
5xx Failed because of a server problem
获取相应状态码
long code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
除了check curl请求的状态 check服务端返回过来的response statusCode
HTTP Range
如果客户端只希望从远程资源中获得前200个字节,或者在中间某个地方需要300个字节时
//只取前两百个字节
curl_easy_setopt(curl, CURLOPT_RANGE, "0-199");
//从索引200开始的文件中的所有内容
curl_easy_setopt(curl, CURLOPT_RANGE, "200-");
//从索引0获取200字节,从索引1000获取200字节
curl_easy_setopt(curl, CURLOPT_RANGE, "0-199,1000-199");
HTTP Authentication
用户名密码验证
curl_easy_setopt(curl, CURLOPT_USERNAME, "joe");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret");
验证请求
客户端并不能决定发送一个验证请求,当服务有资源需要被保护并且需要请求验证,服务器将会返回一个401和WWW-Authenticate:
header,这个header包含了特定的验证方式
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_NEGOTIATE);
Cookie with libcurl
cookie验证
当启用cookie engine时 cookie将存储在相关联的句柄内存中
读取cookie
curl_easy_setopt(easy, CURLOPT_COOKIEFILE, "cookies.txt");
从服务端获取cookie并保存
curl_easy_setopt(easy, CURLOPT_COOKIEJAR, "cookies.txt");
稍后使用curl_easy_cleanup()关闭easy句柄时,所有已知的cookie将被写入给定文件。该文件格式是浏览器曾经使用过的众所周知的“ Netscape cookie文件”格式。
设置自定义cookie 不激活cookie engine
curl_easy_setopt(easy, CURLOPT_COOKIE, "name=daniel; present=yes;");
在其中设置的字符串是将在HTTP请求中发送的原始字符串,并且应采用NAME = VALUE重复序列的格式; 包括分号分隔符
cookie内存区存储大量cookie
Add a cookie to the cookie store
#define SEP "\\t" /* Tab separates the fields */
char *my_cookie =
"example.com" /* Hostname */
SEP "FALSE" /* Include subdomains */
SEP "/" /* Path */
SEP "FALSE" /* Secure */
SEP "0" /* Expiry in epoch time format. 0 == Session */
SEP "foo" /* Name */
SEP "bar"; /* Value */
curl_easy_setopt(curl, CURLOPT_COOKIELIST, my_cookie);
Get all cookies from the cookie store
struct curl_slist *cookies
curl_easy_getinfo(easy, CURLINFO_COOKIELIST, &cookies);
这将返回指向cookie的链接列表的指针,并且每个cookie(再次)被指定为cookie文件格式的一行。该列表已分配给您,因此在应用程序处理完该信息后,请不要忘记调用curl_slist_free_all
Cookie store commands
//清除整个内存记录
curl_easy_setopt(curl, CURLOPT_COOKIELIST, "ALL");
//从内存中删除所有会话cookie(无有效期的cookie)
curl_easy_setopt(curl, CURLOPT_COOKIELIST, "SESS");
//强制将所有cookie写入先前使用CURLOPT_COOKIEJAR指定的文件名
curl_easy_setopt(curl, CURLOPT_COOKIELIST, "FLUSH");
//从先前用CURLOPT_COOKIEFILE指定的文件名强制重新加载cookie
curl_easy_setopt(curl, CURLOPT_COOKIELIST, "RELOAD");
Download
GET方法请求资源
easy = curl_easy_init();
curl_easy_setopt(easy, CURLOPT_URL, "http://example.com/");
curl_easy_perform(easy);
如果使用其他方法请求资源向切随后换回get请求
curl_easy_setopt(easy, CURLOPT_HTTPGET, 1L);
下载相应的返回包头数据 用CURLOPT_HEADER
easy = curl_easy_init();
curl_easy_setopt(easy, CURLOPT_HEADER, 1L);
curl_easy_setopt(easy, CURLOPT_URL, "http://example.com/");
curl_easy_perform(easy);
或者将包头数据存储到文件
easy = curl_easy_init();
FILE *file = fopen("headers", "wb");
curl_easy_setopt(easy, CURLOPT_HEADERDATA, file);
curl_easy_setopt(easy, CURLOPT_URL, "http://example.com/");
curl_easy_perform(easy);
fclose(file);
在开发时设置详细模式,将同时显示发送到stderr的传出和传入标头:
curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
获取一个页面存储到内存
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
CURL *curl_handle;
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = malloc(1);
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL); //整个程序全局只需要初始化一次 多次初始化会出问题
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.example.com/");
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
//curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl_handle);
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else {
printf("%lu bytes retrieved\n", (long)chunk.size);
}
curl_easy_cleanup(curl_handle);
free(chunk.memory);
curl_global_cleanup();
return 0;
}
获取一个文件流的回调函数
//下载文件
static size_t
Writeback(void* pBuffer, size_t nSize, size_t nMemByte, void* pParam)
{
//把下载到的数据以追加的方式写入文件(一定要有a,否则前面写入的内容就会被覆盖了)
FILE* fp = NULL;
fopen_s(&fp, "E:\\test_1.wav", "ab+");
size_t nWrite = fwrite(pBuffer, nSize, nMemByte, fp);
fclose(fp);
return nWrite;
}
如果未设置此回调,则默认情况下libcurl使用'fwrite
Uploadload
http post
HTTP请求将数据传递到服务器的标准方法,使用libcurl,通常可以提供该数据作为指针和长度
curl_easy_setopt(easy, CURLOPT_POSTFIELDS, dataptr);
curl_easy_setopt(easy, CURLOPT_POSTFIELDSIZE, (long)datalength);
使用自定义回调函数
将不断调用回调函数,直到所有数据都传输或者传输失败 如果未设置此回调,则默认情况下libcurl使用'fread'
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <curl/curl.h>
//回调函数的签名 必须按照这个签名实现自己的回调函数
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t retcode;
curl_off_t nread;
retcode = fread(ptr, size, nmemb, stream);
nread = (curl_off_t)retcode;
fprintf(stderr, "*** We read %" CURL_FORMAT_CURL_OFF_T
" bytes from file\n", nread);
return retcode;
}
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
FILE * hd_src;
struct stat file_info;
char *file;
char *url;
if(argc < 3)
return 1;
file = argv[1];
url = argv[2];
stat(file, &file_info);
hd_src = fopen(file, "rb");
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if(curl) {
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* HTTP PUT please */
curl_easy_setopt(curl, CURLOPT_PUT, 1L);
/* specify target URL, and note that this URL should include a file
name, not only a directory */
curl_easy_setopt(curl, CURLOPT_URL, url);
/* now specify which file to upload */
curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);
/* provide the size of the upload, we specicially typecast the value
to curl_off_t since we must be sure to use the correct data size */
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
(curl_off_t)file_info.st_size);
/* Now run off and do what you've been told! */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(hd_src); /* close the local file */
curl_global_cleanup();
return 0;
}
HTTP PUT
CURLOPT_INFILESIZE_LARGE设置上传的大小
curl_easy_setopt(easy, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(easy, CURLOPT_INFILESIZE_LARGE, (curl_off_t) size);
curl_easy_setopt(easy, CURLOPT_READFUNCTION, read_callback);
curl_easy_setopt(easy, CURLOPT_URL, "https://example.com/handle/put");
如果不知道在传输之前不知道传输的大小,对于HTTP 1.0,您必须事先提供大小,HTTP 1.1 你可以添加 标头 Transfer-Encoding: chunked
对于HTTP 2及更高版本,则既不需要大小也不需要额外的标头
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)