LISA HTTP 组件
基于 HTTP 协议的客户端组件,为 ARCS 平台提供完整的 HTTP 通信功能,支持多种请求方法、同步和异步传输、文件下载、分块传输等功能。
功能特性
HTTP 方法支持: 支持 GET、POST、PUT、PATCH、DELETE 等标准 HTTP 方法
传输模式: 支持同步传输、分块传输和文件下载多种传输模式
HTTPS 兼容: 自动将 HTTPS 转换为 HTTP 处理,简化安全连接使用
灵活配置: 支持自定义头部、请求体、超时时间等配置选项
回调机制: 提供灵活的数据接收回调函数,支持流式数据处理
内存管理: 自动内存管理,支持动态分配和释放 HTTP 实例
错误处理: 完善的错误代码体系,便于问题定位和处理
大文件支持: 分块传输模式支持大文件下载,单个数据块最大 4096 字节
配置选项
在 prj.conf 中启用组件:
CONFIG_LISA_HTTP=y # 启用 HTTP 组件
API 接口
生命周期管理
lisa_http_t *lisa_http_init(lisa_http_request_t *req);
lisa_http_err_e lisa_http_cleanup(lisa_http_t *ins);
HTTP 请求接口
lisa_http_err_e lisa_http_perform(lisa_http_t *ins);
lisa_http_err_e lisa_http_download(lisa_http_t *ins);
分块传输接口
lisa_http_err_e lisa_http_perform_chunked(lisa_http_t *ins);
lisa_http_err_e lisa_http_perform_chunked_with_cb(lisa_http_t *ins,
int (*on_chunk)(lisa_http_data_t *));
使用示例
基础 HTTP GET 请求示例
#include "lisa_http.h"
#include "lisa_log.h"
// HTTP 响应数据回调函数
static void http_response_callback(lisa_http_data_t *data)
{
if (data && data->buf && data->len > 0) {
LISA_INFO("收到 HTTP 响应数据,长度: %d", data->len);
// 将数据转换为字符串并输出(假设是文本数据)
char *response = lisa_mem_alloc(data->len + 1);
if (response) {
memcpy(response, data->buf, data->len);
response[data->len] = '\0';
LISA_INFO("响应内容: %s", response);
lisa_mem_free(response);
}
}
}
int basic_http_get_example(void)
{
// 1. 配置 HTTP 请求
lisa_http_request_t request = {
.method = LISA_HTTP_GET,
.url = (uint8_t *)"http://httpbin.org/get",
.headers = NULL, // 使用默认头部
.body = NULL,
.body_len = 0,
.timeout = 10000, // 10秒超时
.user = NULL,
.on_data = http_response_callback,
};
// 2. 创建 HTTP 实例
lisa_http_t *http = lisa_http_init(&request);
if (!http) {
LISA_ERR("创建 HTTP 实例失败");
return -1;
}
// 3. 执行 HTTP 请求
lisa_http_err_e result = lisa_http_perform(http);
if (result == LISA_HTTP_OK) {
LISA_INFO("HTTP 请求执行成功");
} else {
LISA_ERR("HTTP 请求失败,错误代码: %d", result);
}
// 4. 清理资源
lisa_http_cleanup(http);
return (result == LISA_HTTP_OK) ? 0 : -1;
}
HTTP POST 请求示例
#include "lisa_http.h"
#include "lisa_log.h"
#include "cJSON.h"
// POST 请求响应回调函数
static void post_response_callback(lisa_http_data_t *data)
{
if (data && data->buf && data->len > 0) {
char *response = lisa_mem_alloc(data->len + 1);
if (response) {
memcpy(response, data->buf, data->len);
response[data->len] = '\0';
LISA_INFO("POST 响应: %s", response);
// 解析 JSON 响应(如果需要)
cJSON *json = cJSON_Parse(response);
if (json) {
// 处理 JSON 数据
LISA_INFO("JSON 解析成功");
cJSON_Delete(json);
}
lisa_mem_free(response);
}
}
}
int http_post_example(void)
{
// 1. 准备 POST 数据(JSON 格式)
cJSON *json_data = cJSON_CreateObject();
if (!json_data) {
LISA_ERR("创建 JSON 对象失败");
return -1;
}
cJSON_AddStringToObject(json_data, "name", "LISA HTTP Client");
cJSON_AddNumberToObject(json_data, "version", 1.0);
cJSON_AddStringToObject(json_data, "message", "Hello from LISA");
char *json_string = cJSON_PrintUnformatted(json_data);
cJSON_Delete(json_data);
if (!json_string) {
LISA_ERR("JSON 序列化失败");
return -1;
}
// 2. 配置 HTTP POST 请求
lisa_http_request_t request = {
.method = LISA_HTTP_POST,
.url = (uint8_t *)"http://httpbin.org/post",
.headers = (uint8_t *)"Content-Type: application/json\r\n", // 设置 JSON 头部
.body = json_string,
.body_len = strlen(json_string),
.timeout = 15000, // 15秒超时
.user = NULL,
.on_data = post_response_callback,
};
// 3. 创建并执行 HTTP 请求
lisa_http_t *http = lisa_http_init(&request);
if (!http) {
LISA_ERR("创建 HTTP 实例失败");
free(json_string);
return -1;
}
lisa_http_err_e result = lisa_http_perform(http);
// 4. 清理资源
lisa_http_cleanup(http);
free(json_string);
return (result == LISA_HTTP_OK) ? 0 : -1;
}
文件下载示例
#include "lisa_http.h"
#include "lisa_log.h"
#include "lisa_fs.h" // 假设有文件系统接口
// 文件下载上下文
typedef struct {
FILE *file;
uint32_t total_size;
uint32_t downloaded_size;
} download_context_t;
// 文件下载回调函数
static void download_callback(lisa_http_data_t *data)
{
download_context_t *ctx = (download_context_t *)data->user;
if (ctx && ctx->file && data && data->buf && data->len > 0) {
// 写入文件
size_t written = fwrite(data->buf, 1, data->len, ctx->file);
if (written == data->len) {
ctx->downloaded_size += written;
LISA_INFO("下载进度: %d/%d 字节 (%.1f%%)",
ctx->downloaded_size, ctx->total_size,
(float)ctx->downloaded_size * 100.0f / ctx->total_size);
} else {
LISA_ERR("文件写入失败");
}
}
}
int file_download_example(void)
{
// 1. 准备下载上下文
download_context_t download_ctx = {0};
download_ctx.file = fopen("/tmp/downloaded_file.bin", "wb");
if (!download_ctx.file) {
LISA_ERR("无法创建下载文件");
return -1;
}
download_ctx.total_size = 0; // 初始不知道文件大小
// 2. 配置下载请求
lisa_http_request_t request = {
.method = LISA_HTTP_GET,
.url = (uint8_t *)"http://httpbin.org/bytes/1024", // 下载 1KB 数据
.headers = NULL,
.body = NULL,
.body_len = 0,
.timeout = 30000, // 30秒超时
.user = &download_ctx,
.on_data = download_callback,
};
// 3. 执行下载
lisa_http_t *http = lisa_http_init(&request);
if (!http) {
LISA_ERR("创建 HTTP 实例失败");
fclose(download_ctx.file);
return -1;
}
lisa_http_err_e result = lisa_http_download(http);
// 4. 清理资源
fclose(download_ctx.file);
lisa_http_cleanup(http);
if (result == LISA_HTTP_OK) {
LISA_INFO("文件下载完成,总大小: %d 字节", download_ctx.downloaded_size);
} else {
LISA_ERR("文件下载失败,错误代码: %d", result);
}
return (result == LISA_HTTP_OK) ? 0 : -1;
}
分块传输示例
#include "lisa_http.h"
#include "lisa_log.h"
// 分块数据处理回调函数
static int chunk_callback(lisa_http_data_t *data)
{
if (data && data->buf && data->len > 0) {
LISA_INFO("收到数据块,大小: %d 字节", data->len);
// 处理数据块(这里简单计算校验和)
uint8_t checksum = 0;
uint8_t *chunk_data = (uint8_t *)data->buf;
for (int i = 0; i < data->len; i++) {
checksum ^= chunk_data[i];
}
LISA_INFO("数据块校验和: 0x%02X", checksum);
// 检查是否需要继续接收数据
// 返回 0 继续,返回非 0 停止传输
static int chunk_count = 0;
chunk_count++;
if (chunk_count >= 5) {
LISA_INFO("接收到 5 个数据块,停止传输");
return -1; // 停止传输
}
}
return 0; // 继续接收数据
}
int chunked_transfer_example(void)
{
// 1. 配置分块传输请求
lisa_http_request_t request = {
.method = LISA_HTTP_GET,
.url = (uint8_t *)"http://httpbin.org/stream/20", // 流式数据接口
.headers = NULL,
.body = NULL,
.body_len = 0,
.timeout = 20000, // 20秒超时
.user = NULL,
.on_data = NULL, // 使用自定义回调,不需要这个
};
// 2. 创建 HTTP 实例
lisa_http_t *http = lisa_http_init(&request);
if (!http) {
LISA_ERR("创建 HTTP 实例失败");
return -1;
}
// 3. 执行分块传输(使用自定义回调)
lisa_http_err_e result = lisa_http_perform_chunked_with_cb(http, chunk_callback);
// 4. 清理资源
lisa_http_cleanup(http);
if (result == LISA_HTTP_OK) {
LISA_INFO("分块传输完成");
} else {
LISA_ERR("分块传输失败,错误代码: %d", result);
}
return (result == LISA_HTTP_OK) ? 0 : -1;
}
多请求管理示例
#include "lisa_http.h"
#include "lisa_log.h"
// 请求管理结构
typedef struct {
lisa_http_t *http;
char *name;
bool completed;
lisa_http_err_e result;
} http_request_t;
// 统一的响应处理函数
static void unified_response_handler(lisa_http_data_t *data)
{
// 从 user_data 中获取请求管理结构
http_request_t *req_info = (http_request_t *)data->user;
if (req_info) {
req_info->completed = true;
if (data && data->buf && data->len > 0) {
LISA_INFO("请求 '%s' 收到响应,长度: %d", req_info->name, data->len);
} else {
LISA_INFO("请求 '%s' 完成,无响应数据", req_info->name);
}
}
}
int multi_request_example(void)
{
// 1. 定义多个请求
http_request_t requests[3];
const char *urls[] = {
"http://httpbin.org/get",
"http://httpbin.org/uuid",
"http://httpbin.org/ip"
};
const char *names[] = {"GET请求", "UUID请求", "IP请求"};
// 2. 创建并配置多个 HTTP 实例
for (int i = 0; i < 3; i++) {
lisa_http_request_t request = {
.method = LISA_HTTP_GET,
.url = (uint8_t *)urls[i],
.headers = NULL,
.body = NULL,
.body_len = 0,
.timeout = 10000,
.user = &requests[i],
.on_data = unified_response_handler,
};
requests[i].http = lisa_http_init(&request);
requests[i].name = (char *)names[i];
requests[i].completed = false;
requests[i].result = LISA_HTTP_COMMON_ERR;
if (!requests[i].http) {
LISA_ERR("创建请求 '%s' 失败", names[i]);
}
}
// 3. 执行所有请求
for (int i = 0; i < 3; i++) {
if (requests[i].http) {
requests[i].result = lisa_http_perform(requests[i].http);
LISA_INFO("请求 '%s' 执行结果: %d", names[i], requests[i].result);
}
}
// 4. 等待所有请求完成(在实际应用中可能需要更复杂的同步机制)
for (int i = 0; i < 3; i++) {
if (requests[i].completed) {
LISA_INFO("请求 '%s' 已完成", names[i]);
}
}
// 5. 清理所有资源
for (int i = 0; i < 3; i++) {
if (requests[i].http) {
lisa_http_cleanup(requests[i].http);
}
}
return 0;
}
HTTP 方法说明
支持的 HTTP 方法
方法 |
用途 |
请求体 |
适用场景 |
|---|---|---|---|
|
获取资源 |
不支持 |
数据查询、信息获取 |
|
提交数据 |
支持 |
数据创建、表单提交 |
|
更新资源 |
支持 |
完整资源更新 |
|
部分更新 |
支持 |
部分资源更新 |
|
删除资源 |
不支持 |
资源删除 |
传输模式对比
模式 |
同步性 |
适用场景 |
特点 |
|---|---|---|---|
|
同步 |
小数据量、简单请求 |
简单易用,等待完整响应 |
|
同步 |
文件下载 |
优化的文件传输 |
|
异步 |
大数据流处理 |
内部回调,分块处理 |
|
异步 |
自定义数据处理 |
用户控制数据处理流程 |
错误代码说明
错误代码 |
说明 |
可能原因 |
解决方法 |
|---|---|---|---|
|
操作成功 |
- |
- |
|
一般错误 |
参数错误、内存不足 |
检查参数和内存状态 |
|
参数错误 |
URL 为空、回调函数为 NULL |
检查请求配置 |
|
网络错误 |
连接失败、超时 |
检查网络连接和超时设置 |
使用注意事项
参数验证: 创建 HTTP 实例前必须验证 URL 和回调函数不为 NULL
内存管理: 请求体数据在请求执行期间必须保持有效
HTTPS 处理: 组件会自动将 HTTPS URL 转换为 HTTP 处理
超时设置: 根据网络环境和数据大小合理设置超时时间
回调函数: 回调函数应尽量简短,避免阻塞网络处理线程
分块大小: 分块传输时单个数据块最大支持 4096 字节
资源清理: 请求完成后必须调用
lisa_http_cleanup()释放资源错误处理: 所有 API 调用都应检查返回值并处理错误情况
URL 长度: URL 最大长度为 1023 字符(包含结束符)
请求体大小: 请求体最大长度为 1024 字节
线程安全: 每个 HTTP 实例独立工作,但多线程使用时需要注意资源同步
文件操作: 文件下载时需要确保文件系统可用且有写入权限
文件说明
lisa_http.h- HTTP 组件头文件,包含 API 接口和数据结构定义lisa_http.c- HTTP 组件实现文件,基于 HTTPCUsr_api 实现Kconfig- 组件配置选项定义文件CMakeLists.txt- 组件构建配置文件