C语言如何请求JSON数据:从零开始的实用指南
在C语言开发中,处理JSON数据是一项常见需求,尤其是在与RESTful API交互、解析配置文件或进行数据交换时,由于C语言本身没有内置的JSON解析库,我们需要借助第三方库来实现JSON数据的请求与解析,本文将详细介绍如何在C语言中发起HTTP请求获取JSON数据,并使用常用库解析JSON,涵盖环境搭建、代码实现及常见问题解决。
准备工作:选择合适的库
在C语言中处理JSON请求,通常需要两个核心工具:HTTP请求库(用于发送请求并获取JSON响应)和JSON解析库(用于解析返回的JSON字符串),以下是主流库的选择:
HTTP请求库推荐
- libcurl:功能强大的开源客户端URL传输库,支持HTTP、HTTPS、FTP等多种协议,是C语言中最常用的HTTP请求库。
- libcurl的替代方案:如
httplib(轻量级,仅支持HTTP/HTTPS)、libwww(较老,维护较少),但libcurl因稳定性和功能丰富度成为首选。
JSON解析库推荐
- cJSON:超轻量级、零依赖的JSON解析库,API简单易用,适合嵌入式和桌面应用。
- Jansson:功能更全面,支持JSON生成、解析、错误处理等,适合复杂场景。
- Parson:单文件实现,无需编译,适合快速集成。
本文以libcurl发起HTTP请求、cJSON解析JSON为例,讲解完整流程。
环境搭建:安装libcurl和cJSON
安装libcurl
Linux(Ubuntu/Debian)
sudo apt-get update sudo apt-get install libcurl4-openssl-dev
macOS(使用Homebrew)
brew install curl
Windows(vcpkg包管理器)
vcpkg install curl
编译时需链接libcurl库,例如gcc编译:
gcc -o json_request json_request.c -lcurl -lcjson
安装cJSON
Linux(Ubuntu/Debian)
sudo apt-get install libcjson-dev
macOS(使用Homebrew)
brew install cJSON
Windows(vcpkg包管理器)
vcpkg install cJSON
若手动编译cJSON,可从GitHub仓库下载源码,执行make生成静态库(.a文件)。
核心步骤:发起HTTP请求并解析JSON
步骤1:使用libcurl发起HTTP请求
libcurl的核心流程包括:初始化CURL句柄、设置请求选项(如URL、回调函数)、执行请求、清理资源,以下是一个GET请求示例,获取公开API的JSON数据(以JSONPlaceholder为例):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
// 回调函数:处理服务器返回的数据
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
char *mem = (char *)userp;
// 动态扩展内存(简单示例,实际需更健壮的内存管理)
mem = realloc(mem, realsize + 1);
if (mem == NULL) {
fprintf(stderr, "内存分配失败\n");
return 0;
}
memcpy(mem, contents, realsize);
mem[realsize] = '\0';
return realsize;
}
// 发起HTTP GET请求,返回JSON字符串
char* http_get_json(const char *url) {
CURL *curl;
CURLcode res;
char *json_data = malloc(1); // 初始分配1字节
if (json_data == NULL) {
fprintf(stderr, "初始内存分配失败\n");
return NULL;
}
json_data[0] = '\0';
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)json_data);
// 设置超时(秒)
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
// 禁用SSL证书验证(仅测试环境,生产环境需配置CA证书)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
res = curl_easy_perform(curl);
// 检查请求是否成功
if (res != CURLE_OK) {
fprintf(stderr, "请求失败: %s\n", curl_easy_strerror(res));
free(json_data);
json_data = NULL;
} else {
long response_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code != 200) {
fprintf(stderr, "HTTP错误码: %ld\n", response_code);
free(json_data);
json_data = NULL;
}
}
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return json_data;
}
步骤2:使用cJSON解析JSON字符串
假设API返回的JSON数据为:
[
{
"userId": 1,
"id": 1,: "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
]
使用cJSON解析上述数据的代码如下:
#include <cjson/cJSON.h>
void parse_json(const char *json_string) {
if (json_string == NULL) {
fprintf(stderr, "JSON字符串为空\n");
return;
}
cJSON *root = cJSON_Parse(json_string);
if (root == NULL) {
fprintf(stderr, "JSON解析失败: %s\n", cJSON_GetErrorPtr());
return;
}
// 检查JSON是否是数组
if (!cJSON_IsArray(root)) {
fprintf(stderr, "JSON数据不是数组\n");
cJSON_Delete(root);
return;
}
// 遍历数组中的每个对象
cJSON *item = NULL;
cJSON_ArrayForEach(item, root) {
if (cJSON_IsObject(item)) {
cJSON *userId = cJSON_GetObjectItem(item, "userId");
cJSON *id = cJSON_GetObjectItem(item, "id");
cJSON *title = cJSON_GetObjectItem(item, "title");
if (cJSON_IsNumber(userId) && cJSON_IsNumber(id) && cJSON_IsString(title)) {
printf("ID: %d\n", id->valueint);
printf("用户ID: %d\n", userId->valueint);
printf("标题: %s\n", title->valuestring);
printf("----------------------\n");
}
}
}
cJSON_Delete(root); // 释放JSON内存
}
步骤3:整合完整代码
将HTTP请求和JSON解析整合,完整示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include <cjson/cJSON.h>
// 回调函数:处理服务器返回的数据
size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
char *mem = (char *)userp;
mem = realloc(mem, realsize + 1);
if (mem == NULL) {
fprintf(stderr, "内存分配失败\n");
return 0;
}
memcpy(mem, contents, realsize);
mem[realsize] = '\0';
return realsize;
}
// 发起HTTP GET请求,返回JSON字符串
char* http_get_json(const char *url) {
CURL *curl;
CURLcode res;
char *json_data = malloc(1);
if (json_data == NULL) {
fprintf(stderr, "初始内存分配失败\n");
return NULL;
}
json_data[0] = '\0';
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)json_data);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);


还没有评论,来说两句吧...