REST接口调用客户端开发库例子

最近在写微服务相关的东西,微服务对外公布的rest api如何让不同语言的开发者方便调用呢?本文简单实现了个rest接口客户端调用库,可简单满足vc、qt、java开发者通过指定网关及其代理的微服务名访问具体的rest接口的需求。

vc

vc下用的是大名鼎鼎的libcurl库封装rest调用,libcurl怎么用vc编译看上一篇文章,下面直接上代码吧

restcli.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef RESTCLI_H
#define RESTCLI_H

#include <iostream>
#include <string>
#include <map>
using namespace std;

class RestClient
{
public:
RestClient();
RestClient(string address, int port, string serviceName);
void SetAuth(string appKey, string appSecret);
void SetTimeout(int connTimeout, int timeout);
bool Get(string path, string &result);
bool Post(string path, string &result, string postData="");
protected:
void genBasePath();
void genAuthParam();
string getUrl(string path);
private:
string address;
int port;
string serviceName;
string appKey;
string appSecret;
int connTimeout;
int timeout;
string basePath;
string authParam;
};
#endif // RESTCLI_H

restcli.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "restcli.h"
#include "curl.h"
#include <sstream>

static int writer(char *data, size_t size, size_t nmemb, std::string *writerData)
{
if(writerData == NULL)
return 0;
writerData->append(data, size*nmemb);
return size * nmemb;
}

RestClient::RestClient()
{
this->address = "localhost";
this->port = 80;
this->serviceName = "";
this->appKey = "";
this->appSecret = "";
this->connTimeout = -1;
this->timeout = -1;
genBasePath();
genAuthParam();
}
RestClient::RestClient(string address, int port, string serviceName)
{
this->address = address;
this->port = port;
this->serviceName = serviceName;
this->appKey = "";
this->appSecret = "";
this->connTimeout = -1;
this->timeout = -1;
genBasePath();
genAuthParam();
}
void RestClient::genBasePath()
{
ostringstream osPort;
osPort<<this->port;
this->basePath = "http://" + this->address + ":" + osPort.str() + "/";
if (this->serviceName.size() > 0)
this->basePath += this->serviceName + string("/");
}
void RestClient::genAuthParam()
{
if (appKey.size() > 0) {
authParam = "appKey=" + appKey + "&appSecret=" + appSecret;
}
}
string RestClient::getUrl(string path)
{
string url = basePath + path;
if (authParam.size() == 0)
return url;
int pos = path.find("?");
if (pos >= 0) {
url += "&" + authParam;
} else {
url += "?" + authParam;
}
return url;
}
void RestClient::SetAuth(string appKey, string appSecret)
{
this->appKey = appKey;
this->appSecret = appSecret;
}
void RestClient::SetTimeout(int connTimeout, int timeout)
{
this->connTimeout = connTimeout;
this->timeout = timeout;
}

bool RestClient::Get(string path, string &result)
{
CURLcode code;
CURL* curl = curl_easy_init();
if (curl == NULL)
return false;
string url = getUrl(path);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, this->connTimeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, this->timeout);
code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(code != CURLE_OK)
return false;

return true;
}
bool RestClient::Post(string path, string &result, string postData)
{
CURLcode code;
CURL* curl = curl_easy_init();
if (curl == NULL)
return false;
curl_easy_setopt(curl, CURLOPT_URL, getUrl(path).c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, this->connTimeout);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, this->timeout);
code = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(code != CURLE_OK)
return false;

return true;
}

qt

之所以用libcurl进行http请求处理的一个重要原因就是为了想在vc下和qt下可以复用一套代码,所以qt的代码和vc的是一样的。具体qt的工程文件x.pro怎么写见上一篇文章

java

java处理http请求就简单多了,如果是springMVC工程下直接用个restTemplate就完成了,下面还是用java下最普遍使用的httpclient库实现。我建立maven工程,引入httpclient依赖4.5.5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
public class RestClient {
String address = "localhost";
int port = 80;
String serviceName = "";
String appKey = "";
String appSecret = "";
int connTimeout = -1;
int timeout = -1;
String basePath = "";
String authParam = "";

public RestClient() {
genBasePath();
genAuthParam();
}

public RestClient(String address, int port, String serviceName) {
this.address = address;
this.port = port;
this.serviceName = serviceName;
genBasePath();
genAuthParam();
}

public void SetAuth(String appKey, String appSecret) {
this.appKey = appKey;
this.appSecret = appSecret;
}

public void SetTimeout(int connTimeout, int timeout) {
this.connTimeout = connTimeout;
this.timeout = timeout;
}

public boolean Get(String path, StringBuilder result) {
boolean ret = false;
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(connTimeout)
.setConnectionRequestTimeout(connTimeout)
.setSocketTimeout(timeout).setRedirectsEnabled(true).build();
String url = getUrl(path);
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(requestConfig);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
int statusCode = httpResponse.getStatusLine().getStatusCode();
String s = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
if (statusCode == 200) {
result.append(s);
ret = true;
} else {
ret = false;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}

public boolean Post(String path, StringBuilder result, String postData) {
boolean ret = false;
CloseableHttpClient httpClient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(connTimeout)
.setConnectionRequestTimeout(connTimeout)
.setSocketTimeout(timeout).setRedirectsEnabled(true).build();
String url = getUrl(path);
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(requestConfig);
List<BasicNameValuePair> list = new ArrayList<BasicNameValuePair>();
String[] params = postData.split("&");
for (String param : params) {
String[] nv = param.split("=");
if (nv.length == 2) {
list.add(new BasicNameValuePair(nv[0], nv[1]));
}
}
try {
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,
"UTF-8");
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
int statusCode = httpResponse.getStatusLine().getStatusCode();
String s = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
if (statusCode == 200) {
result.append(s);
ret = true;
} else {
ret = false;
}
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}

private String getUrl(String path) {
String url = basePath + path;
if (authParam.length() == 0)
return url;
int pos = path.indexOf("?");
if (pos >= 0) {
url += "&" + authParam;
} else {
url += "?" + authParam;
}
return url;
}

private void genAuthParam() {
if (appKey.length() > 0) {
authParam = "appKey=" + appKey + "&appSecret=" + appSecret;
}
}

private void genBasePath() {
if (port == 80) {
this.basePath = "http://" + this.address + "/";
} else {
this.basePath = "http://" + this.address + ":" + port + "/";
}
if (this.serviceName.length() > 0)
this.basePath += this.serviceName + "/";
}

public static void testGet() throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://www.baidu.com/");
HttpResponse httpRes = httpClient.execute(httpGet);
String result = EntityUtils.toString(httpRes.getEntity(), "UTF-8");
System.out.println(result);
httpClient.close();
}

public static void main(String[] args) throws Exception {
// RestClient.testGet();
RestClient rc = new RestClient("www.baidu.com", 80, "");
StringBuilder sb = new StringBuilder("");
boolean b = rc.Get("", sb);

System.out.println(b);
System.out.println(sb);
}
}

建maven工程的一个重要原因是想封装的rest访问库只要提供一个jar包就可以,如果普通工程恐怕要附带提供其他如httpclient.jar的包。~标记一下以后写maven的文章~

参考文章

*下面这些文章是我写上面这些时看过的,记录下来以备后看
libcurl

qt

httpclient