libcurl实现HTTP

2023-05-16

关于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(使用前将#替换为@)

libcurl实现HTTP 的相关文章

  • 如何使用 python 的 http.client 准确读取一个响应块?

    Using http client在 Python 3 3 或任何其他内置 python HTTP 客户端库 中 如何一次读取一个分块 HTTP 响应一个 HTTP 块 我正在扩展现有的测试装置 使用 python 编写 http clie
  • Node.js 未处理的“错误”事件

    我编写了一个简单的代码并将其保存在文件 try js 中 var http require http var makeRequest function message var options host localhost port 8080
  • 使用 WCF 支持“application/x-www-form-urlencoded”发布数据的最佳方式?

    我正在基于 W3C 规范构建 WCF 服务 该规范定义了接受 application x www form urlencoded 发布数据的 RESTful Web 服务端点 默认情况下 WCF 不支持这种类型的消息编码 我发现了许多创建如
  • 自定义 HTTP 标头:命名约定

    我们的一些用户要求我们将与其帐户相关的数据包含在HTTP 标头我们向他们发送的请求 甚至是他们从我们的 API 获得的响应 添加自定义 HTTP 标头的一般约定是什么 naming format etc 另外 请随意发布您在网络上偶然发现的
  • 以下 Android HTTP 示例/教程 - 为网络活动实现异步任务的问题

    我正在尝试遵循有关发布 HTTP 数据的教程 但是由于 IO 线程上的网络活动 它强制关闭主线程 因此我尝试实现 AsyncTask 正如其他几个有用的 SO 用户所建议的那样 但是我已经屠宰了代码 整个辣酱玉米卷饼的力量就向我逼近了 ht
  • 适用于 Objective-C / iPhone 的良好 HTTP 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 UPDATE 这个问题显然已经过时了 参见日期 我建议只使用现代 iOS7 功能 例如 NSURLSession 我想 这个问题是为了历史
  • android httprequest java.net.UnknownHostException

    我想用android发出http请求 是使用这个 void testHTTP HttpClient httpClient new DefaultHttpClient HttpUriRequest request new HttpPost h
  • 尝试克隆一个 git 存储库,但它卡在克隆到中

    我使用的是 Windows 10版本 10 0 19042 内部版本 19042 GIT Ver 2 32当尝试使用 git bash 执行以下命令时git clone depth 1 b carla https github com Ca
  • Zoopla 沙箱出现 cURL http 标头错误

    我正在为房地产经纪人开发代码 以通过他们的数据源将房产上传到 Zoopla 我在将所需的配置文件添加到所需的 http 标头时遇到问题 文档中唯一的示例是来自 Linux 的测试 echo branch reference test cur
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 如何在c++中使用libcurl发送POST请求并接收它?

    我正在使用 c libcurl 向网页发送 POST 请求 但我正在努力测试它 使用的代码是 include
  • 无效数据的 REST 响应代码

    如果出现以下情况 应将什么响应代码传递给客户端 用户注册时传递了无效数据 例如电子邮件格式错误 用户名 电子邮件已存在 我选择了403 我还发现了以下我觉得可以用的 维基百科 412 前提条件失败 服务器不满足请求者要求的先决条件之一 提出
  • 为什么我在将数据上传到数据库时不断看到“正在重置断开的连接”?

    我正在通过 REST API 将数亿个项目从 Heroku 上的云服务器上传到 AWS EC2 中的数据库 我正在使用 Python 并且经常在日志中看到以下 INFO 日志消息 requests packages urllib3 conn
  • HTTP请求的内容长度>正文大小

    我正在管理一个网站 该网站过去几个月在使用 MVC 3 0 ASP net 构建的 IIS 7 5 上运行良好 当我们的 AJAX POST 请求 通过 jQuery 触发 因发布的 JSON 被截断而失败时 我们时不时地会遇到一个问题 到
  • eBay API 调用不适用于 UPC/EAN

    eBay 的 API findItemsByProduct 操作适用于 UPC 和 EAN 但不幸的是它不起作用 例如 下面的 HTTP GET 请求会抛出 无效的产品 ID 值 错误41 Note 请将 SECURITY APPNAME
  • Crystal lang如何从http获取二进制文件

    In Ruby require open uri download open http example com download pdf IO copy stream download my file pdf 如何在水晶中做同样的事情 我们
  • 如何在 G-WAN 中添加 HTTP/2

    我想知道是否可以通过使用解决方案 nghttp2 https nghttp2 org https nghttp2 org 很抱歉这么晚才回答 出于某种原因 Stackoverflow 没有通知我们这个问题 我之所以找到它只是因为收到了更新的
  • Android 套接字和 HTTP 响应标头

    有趣的是 我可能无意中找到了解决方案是否可以使用普通套接字连接发送 HTTP 请求并接收没有标头的响应 https stackoverflow com questions 8320574 我希望我忽略了一些东西 无论如何 我正在连接到 We
  • LibCurl SFTP 重命名文件

    解决了 经过更多转换后 通过使用 重命名 作为引用命令 它需要包含原始名称的完整路径和包含重命名目标的完整路径 在我其他失败的尝试中 我没有尝试过这条路 大家好 我尝试了所有不同的组合 但一直失败 不知道我错过了什么 我正在尝试使用 Lib
  • 如何解析来自基于 C 的 Web 服务器的 HTTP 请求

    我有一个编程项目 我必须创建一个处理 HTTP 请求的多线程 Web 服务器 我刚刚学习了套接字编程 并且运行了一个客户端和一个服务器 我想知道解析 HTTP 请求标头的最佳方法是什么 我看到了这个 如何用C 解析http请求 https

随机推荐

  • 自己组装Pixhawk F450无人机的一些细节

    首先参考文档为 xff1a 1 https mp weixin qq com s VXKU kIB v i0AX3zgtLig 2 https mp weixin qq com s Qzzl dQ6Tz2pXNp7Oj0lTg 3 http
  • 电机和桨叶要搭配选择

    拍自 四旋翼无人机的制作与飞行
  • 接收机PPM与SBUS

    最开始是自己弄ACfly的飞控时发现插接收机有两个位置 xff0c 一个PPM一个SBUS xff0c 我想直接移植Pixhawk的接收机或者无名的接收机到ACfly模块上 我最后发现Pixhawk和无名的也是留了两个给接收机 xff08
  • 现在发现如果无人机的电机不同,浆可能是不能混用的。

    现在发现如果无人机的电机不同 xff0c 浆可能是不能混用的 孔位不同 xff0c 我之前在无名那里买了很多浆 xff0c 觉得这次F330的浆没了可以用那个替 xff0c 我刚刚试了下发现插不进去 xff0c 不能通用 包括我刚才在店家那
  • 无人机电池似乎可以并联,串联组合

    之前总是见到这种奇怪的线 xff0c 一直不知道作什么用 xff0c 现在大概清楚了 是不是这样可以实现更长时间的续航 xff0c 我之前再ACfly的群里看到一个人的六轴是上面放了两个电池的 xff0c 他这可能也是并联的
  • 任务的三要素是任务主体函数,任务栈和任务控制块

    任务的三要素是任务主体函数 xff0c 任务栈和任务控制块 由xTaskCreateStatic 函数来把三者联合起立 下面拍自野火的 FreeRTOS内核实现与应用开发实战指南
  • 如何用Realsense D435i运行VINS-Mono等VIO算法 获取IMU同步数据

    摘自 xff1a https blog csdn net qq 41839222 article details 86552367 如何用Realsense D435i运行VINS Mono等VIO算法 获取IMU同步数据 Manii 20
  • Opencv安装与环境配置

    转载自 xff1a https blog csdn net sm16111 article details 81238324 Opencv安装与环境配置 代码敌敌畏 2018 07 27 15 46 24 50411 收藏 94 分类专栏
  • 串口参数详解:波特率,数据位,停止位,奇偶校验位

    转载自 xff1a https blog csdn net sinat 35705952 article details 89034455 串口参数详解 xff1a 波特率 xff0c 数据位 xff0c 停止位 xff0c 奇偶校验位 W
  • cpp-httplib库简单原理,听说你还不会开源库?

    cpp httplib库的原理 听说你还不会开源库 xff1f 介绍httplib h头文件的处理流程httplib h头文件的组成httplib h头文件搭建服务端与客户端的原理Get接口listen 0 0 0 0 8989 接口 介绍
  • UART串口调试

    转载自 xff1a https www secpulse com archives 157847 html UART串口调试 脉搏文库 TideSec 2021 04 23 4 356 0x00前言 前段时间陆陆续续的对光猫 路由器 摄像头
  • visca协议及其实现的简单认识

    转载自 xff1a https latelee blog csdn net article details 35811777 visca协议及其实现的简单认识 李迟 2014 06 30 14 09 01 7064 收藏 12 分类专栏 x
  • C语言实现的一个简单的HTTP程序

    转载自 xff1a https www cnblogs com xuwenmin888 archive 2013 05 04 3059282 html C语言实现的一个简单的HTTP程序 以下是参考 lt winsock网络编程经络 gt
  • ideavim使用

    IdeaVim 常用操作 IdeaVim简介 IdeaVim是IntelliJ IDEA的一款插件 xff0c 他提高了我们写代码的速度 xff0c 对代码的跳转 xff0c 查找也很友好 安装之后它在 Tools gt Vim Emula
  • CAN总线——数据传输故障处理

    最近遇到CAN总线通讯的问题 上位机为arm板 xff0c 核心板为Cortex A9处理器 Linux内核 下位机为5块 STM32板 现象为 xff1a 如果上位机只接收数据 xff0c 一切通讯正常 当上位机下发命令 xff0c 那么
  • 升级构建工具,从Makefile到CMake

    更多博文 xff0c 请看音视频系统学习的浪漫马车之总目录 C C 43 43 编译 浅析C C 43 43 编译本质 一篇文章入门C C 43 43 自动构建利器之Makefile 升级构建工具 xff0c 从Makefile到CMake
  • RTKLIB简介

    RTKLIB是全球导航卫星系统GNSS global navigation satellite system 的标准 amp 精密定位开源程序包 xff0c RTKLIB由日本东京海洋大学 xff08 Tokyo University of
  • zzuli OJ 1038: 绝对值最大

    Description 输入3个整数 xff0c 输出绝对值最大的那个数 Input 输入包含3个int范围内的整数 xff0c 用空格隔开 Output 输出三个数中绝对值最大的数 xff0c 单独占一行 若绝对值最大的数不唯一 xff0
  • md5sum

    ERROR 1550456422 414780061 Client Lidar cipv 213 wants topic rs percept result to have datatype md5sum autodrive msgs Pe
  • libcurl实现HTTP

    关于libcurl的相关函数介绍以及参数详见官方说明 https curl haxx se libcurl c example html HTTP Request 一个http请求包含方法 路径 http版本 请求包头 请求方法 GET H