内容简介:C语言实现GET请求调用API
使用 python
可以很容易地实现简单的 HTTP
请求,因为系统库封装了构建 HTTP
请求报文的底层操作,面向用户的是简单地函数调用,而通过 C语言 实现 HTTP
请求必须了解 HTTP
协议的原理,这里推荐经典的 《HTTP权威指南》 和入门的 《图解HTTP》
HTTP协议简介
HTTP报文分为请求报文和响应报文,报文分为三个部分:起始行,首部块和正文主题,这里着重谈谈请求报文的构建
另外,使用浏览器的调试工具->网络选项也能直观地分析每个HTTP请求的特征
C实现HTTP请求的细节
请求报文
请求报文的格式如下:
<method> <requests-URL> <version> <headers> <entire body>
method
代表对服务器资源获取的动作,常见的有 get
和 post
。
requests-URL
代表请求的统一资源定位符,也就是完整的网页链接。
version
是 HTTP
版本,目前已 HTTP1.1
最为常见。
headers
表示请求报文的首部,常见的防盗链 refer
,浏览器信息 user-agent
等等都在这里定义,注意这里的每一项属性参数以每行末尾的 \n\r
来分隔。
响应报文
和请求报文类似,只介绍其独特的地方
<version> <status> <reason-phrase> <headers> <entire body>
status
和 reason-phrase
表示状态码和原因短语,比较常见的就是 200 OK
, 404 Not Found
, 502 Bad Gateway
entire body
报文的实体部分,一般来说就是发往浏览器的整个 HTML
文件,当然还有图片,二进制文件等等其他一些资源。
GET请求
创建socket
//定义的缓冲区用来存放socket发送和接受的数据 也就是HTTP请求和响应报文 char buff[2048]; int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if ( sockfd < 0 ) { printf( "create socket error!\n" ); exit( -1 ); } struct sockaddr_in serveraddr; memset( &serveraddr, 0, sizeof(serveraddr) ); serveraddr.sin_family = AF_INET; // HTTP服务 TCP 80端口 serveraddr.sin_port = htons( 80 ); // apis.map.qq.com 解析地址 inet_pton( AF_INET, "182.254.11.29", &serveraddr.sin_addr.s_addr ); if ( connect( sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr) ) < 0 ) { printf( "connect error!\n" ); exit( -2 ); } memset( buff, 0, sizeof(buff) );
测试用例还是上回 腾讯地图 的 API
,注册过后拿到开发密钥XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
注意下应用类型选择 浏览器 ,名字什么的可以随便填
根据API说明构建HTTP请求报文
snprintf( buff, sizeof(buff) - 1, "GET /ws/geocoder/v1/?location=%s,%s&key=XXXXX-XXXXX-XXXXX-XXXXX-XXXXX&get_poi=1&coord_type=3 HTTP/1.1\r\n" "Host: apis.map.qq.com\r\n" "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" "\r\n", argv[1], argv[2] );
发送请求
if ( write( sockfd, buff, strlen( buff ) ) != strlen( buff ) ) { return(-1); /* 发送出错返回-1 */ } memset( buff, 0, sizeof(buff) ); size_t size; if ( (size = read( sockfd, buff, sizeof(buff) ) ) < 0 ) /* 从服务器端读取 */ { return(-1); } printf( "HTTP响应报文:\n%s\n", buff ); close( sockfd ); }
响应实例
HTTP响应报文: HTTP/1.1 200 OK X-LIMIT: current_qps=1; limit_qps=5; current_pv=21; limit_pv=10000 Content-Type: application/json; charset=utf-8 Content-Length: 9528 Date: Mon, 29 May 2017 00:27:04 GMT Connection: keep-alive { "status": 0, "message": "query ok", "request_id": "6274752708360945856", "result": { "location": { "lat": 30.542301, "lng": 114.392483 }, "address": "湖北省武汉市武昌区东湖东路", "formatted_addresses": { "recommend": "武昌区东湖生态旅游风景区东湖", "rough": "武昌区东湖生态旅游风景区东湖" ...
响应报文长度可能会超过 buff
的长度,所以会显示不全
数据处理
拿到响应报文后,还需要把有用的地理信息从字符数组中提取出来,这里我只提取 recommend
和 rough
的值,如果需要解析整个 JSON
需要用到 cJson
库。
匹配处理
字符数组匹配子串用的是 strstr()
函数
int repResolve( char *rep, char *recmd, char* rough ) { //p q接受匹配后的起始地址 char * p = strstr( rep, "recommend" ); char * q = strstr( rep, "rough" ); if ( p ) { // recommend": " r到"一共13个字符 p = p + 13; // 地名" 一直匹配到引号的结束 while (!((*p) == '\"')) { //字符串复制 *recmd++ = *p++; } //字符串末尾补0 *recmd = '\0'; } if ( q ) { q += 9; while (!((*q) == '\"')) { *rough++ = *q++; } *rough = '\0'; } return(0); }
完整代码
#include <string.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> //填写你自己申请的APIkey const char* apikey=""; int repResolve( char *rep, char *recmd, char* rough ) { //p q接受匹配后的起始地址 char * p = strstr( rep, "recommend" ); char * q = strstr( rep, "rough" ); if ( p ) { // recommend": " r到"一共13个字符 p = p + 13; // 地名" 一直匹配到引号的结束 while (!((*p) == '\"')) { //字符串复制 *recmd++ = *p++; } //字符串末尾补0 *recmd = '\0'; } if ( q ) { q += 9; while (!((*q) == '\"')) { *rough++ = *q++; } *rough = '\0'; } return(0); } int main( int argc, char **argv ) { char buff[2048] = { '\0' }; char recmd[512] = { '\0' }; char rough[512] = { '\0' }; int sockfd = socket( AF_INET, SOCK_STREAM, 0 ); if ( sockfd < 0 ) { printf( "create socket error!\n" ); exit( -1 ); } struct sockaddr_in serveraddr; memset( &serveraddr, 0, sizeof(serveraddr) ); serveraddr.sin_family = AF_INET; serveraddr.sin_port = htons( 80 ); inet_pton( AF_INET, "182.254.11.29", &serveraddr.sin_addr.s_addr ); /* inet_pton(AF_INET, "apis.map.qq.com", &serveraddr.sin_addr.s_addr); */ if ( connect( sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr) ) < 0 ) { printf( "connect error!\n" ); exit( -2 ); } memset( buff, 0, sizeof(buff) ); snprintf( buff, sizeof(buff) - 1, "GET /ws/geocoder/v1/?location=%s,%s&key=%s&get_poi=1&coord_type=3 HTTP/1.1\r\n" "Host: apis.map.qq.com\r\n" "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n" "\r\n", argv[1], argv[2] ,apikey ); if ( write( sockfd, buff, strlen( buff ) ) != strlen( buff ) ) { return(-1); } memset( buff, 0, sizeof(buff) ); size_t size; if ( (size = read( sockfd, buff, sizeof(buff) ) ) < 0 ) { return(-1); } /*步骤4:关闭socket*/ printf( "\nTCP响应长度: %d\n", size ); printf( "HTTP响应报文长度: %d\n", strlen( buff ) ); //printf( "HTTP响应报文:\n%s\n", buff ); printf("HTTP响应报文:\n%.*s\n", 290, buff); repResolve( buff, recmd, rough ); printf( "当前坐标: \n%s %s\n", argv[1], argv[2] ); printf( "当前位置: \n\t%s\n", recmd ); printf( "\t%s\n", rough ); close( sockfd ); }
第一个参数接受纬度,第二个参数接受精度,请求效果如下
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用 SpringAOP 获取一次请求流经方法的调用次数和调用耗时
- 使用 SpringAOP 获取一次请求流经方法的调用次数和调用耗时
- PHP如何发送GET/POST请求调用API
- 为何一次请求会有两次HttpServlet:service调用?
- 直观讲解-RPC调用和HTTP调用的区别
- 调用链系列一:解读UAVStack中的调用链技术
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithm Analysis in Java
Mark A. Weiss / Pearson / 2011-11-18 / GBP 129.99
Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course wa......一起来看看 《Data Structures and Algorithm Analysis in Java》 这本书的介绍吧!