Browse Source

Add axios

hewei.it 4 years ago
parent
commit
7c80ba689c
8 changed files with 388 additions and 21 deletions
  1. 1 0
      Makefile.vars
  2. 52 2
      README-CN.md
  3. 52 2
      README.md
  4. 1 0
      cmake/vars.cmake
  5. 76 1
      examples/http_client_test.cpp
  6. 4 2
      http/HttpMessage.cpp
  7. 192 0
      http/client/axios.h
  8. 10 14
      http/client/requests.h

+ 1 - 0
Makefile.vars

@@ -77,6 +77,7 @@ HTTP_HEADERS =  http/httpdef.h\
 
 HTTP_CLIENT_HEADERS =   http/client/http_client.h\
 						http/client/requests.h\
+						http/client/axios.h\
 						http/client/WebSocketClient.h\
 
 HTTP_SERVER_HEADERS =   http/server/HttpService.h\

+ 52 - 2
README-CN.md

@@ -101,6 +101,8 @@ bin/curl -v -X DELETE localhost:8080/group/test/user/123
 ### HTTP
 #### HTTP服务端
 见[examples/http_server_test.cpp](examples/http_server_test.cpp)
+
+golang gin style
 ```c++
 #include "HttpServer.h"
 
@@ -142,6 +144,8 @@ int main() {
 ```
 #### HTTP客户端
 见[examples/http_client_test.cpp](examples/http_client_test.cpp)
+
+python requests style
 ```c++
 #include "requests.h"
 
@@ -150,7 +154,6 @@ int main() {
     if (resp == NULL) {
         printf("request failed!\n");
     } else {
-        printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
 
@@ -158,7 +161,6 @@ int main() {
     if (resp == NULL) {
         printf("request failed!\n");
     } else {
-        printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
 
@@ -166,6 +168,54 @@ int main() {
 }
 ```
 
+js axios style
+```
+#include "axios.h"
+
+int main() {
+    const char* strReq = R"(
+    {
+        "method": "POST",
+        "url": "http://127.0.0.1:8080/echo",
+        "params": {
+            "page_no": "1",
+            "page_size": "10"
+        },
+        "headers": {
+            "Content-Type": "application/json"
+        },
+        "body": {
+            "app_id": "123456",
+            "app_secret": "abcdefg"
+        }
+    }
+    )";
+
+    // sync
+    auto resp = axios::axios(strReq);
+    if (resp == NULL) {
+        printf("request failed!\n");
+    } else {
+        printf("%s\n", resp->body.c_str());
+    }
+
+    // async
+    int finished = 0;
+    axios::axios(strReq, [&finished](const HttpResponsePtr& resp) {
+        if (resp == NULL) {
+            printf("request failed!\n");
+        } else {
+            printf("%s\n", resp->body.c_str());
+        }
+        finished = 1;
+    });
+
+    // wait async finished
+    while (!finished) hv_sleep(1);
+    return 0;
+}
+```
+
 #### HTTP压测
 ```shell
 # webbench (linux only)

+ 52 - 2
README.md

@@ -99,6 +99,8 @@ bin/curl -v -X DELETE localhost:8080/group/test/user/123
 ### HTTP
 #### http server
 see [examples/http_server_test.cpp](examples/http_server_test.cpp)
+
+golang gin style
 ```c++
 #include "HttpServer.h"
 
@@ -140,6 +142,8 @@ int main() {
 ```
 #### http client
 see [examples/http_client_test.cpp](examples/http_client_test.cpp)
+
+python requests style
 ```c++
 #include "requests.h"
 
@@ -148,7 +152,6 @@ int main() {
     if (resp == NULL) {
         printf("request failed!\n");
     } else {
-        printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
 
@@ -156,7 +159,6 @@ int main() {
     if (resp == NULL) {
         printf("request failed!\n");
     } else {
-        printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
 
@@ -164,6 +166,54 @@ int main() {
 }
 ```
 
+js axios style
+```
+#include "axios.h"
+
+int main() {
+    const char* strReq = R"(
+    {
+        "method": "POST",
+        "url": "http://127.0.0.1:8080/echo",
+        "params": {
+            "page_no": "1",
+            "page_size": "10"
+        },
+        "headers": {
+            "Content-Type": "application/json"
+        },
+        "body": {
+            "app_id": "123456",
+            "app_secret": "abcdefg"
+        }
+    }
+    )";
+
+    // sync
+    auto resp = axios::axios(strReq);
+    if (resp == NULL) {
+        printf("request failed!\n");
+    } else {
+        printf("%s\n", resp->body.c_str());
+    }
+
+    // async
+    int finished = 0;
+    axios::axios(strReq, [&finished](const HttpResponsePtr& resp) {
+        if (resp == NULL) {
+            printf("request failed!\n");
+        } else {
+            printf("%s\n", resp->body.c_str());
+        }
+        finished = 1;
+    });
+
+    // wait async finished
+    while (!finished) hv_sleep(1);
+    return 0;
+}
+```
+
 #### http benchmark
 ```shell
 # webbench (linux only)

+ 1 - 0
cmake/vars.cmake

@@ -85,6 +85,7 @@ set(HTTP_HEADERS
 set(HTTP_CLIENT_HEADERS
     http/client/http_client.h
     http/client/requests.h
+    http/client/axios.h
     http/client/WebSocketClient.h)
 
 set(HTTP_SERVER_HEADERS

+ 76 - 1
examples/http_client_test.cpp

@@ -1,4 +1,14 @@
+/*
+ * @build   make examples
+ *
+ * @server  bin/http_server_test 8080
+ *
+ * @client  bin/http_client_test
+ *
+ */
+
 #include "requests.h"
+#include "axios.h"
 
 #include "hthread.h" // import hv_gettid
 
@@ -65,6 +75,70 @@ static void test_requests() {
         printf("%d %s\r\n", resp->status_code, resp->status_message());
         printf("%s\n", resp->body.c_str());
     }
+
+    // async
+    /*
+    int finished = 0;
+    Request req(new HttpRequest);
+    req->url = "http://127.0.0.1:8080/echo";
+    req->method = HTTP_POST;
+    req->body = "This is an async request.";
+    req->timeout = 10;
+    requests::async(req, [&finished](const HttpResponsePtr& resp) {
+        if (resp == NULL) {
+            printf("request failed!\n");
+        } else {
+            printf("%d %s\r\n", resp->status_code, resp->status_message());
+            printf("%s\n", resp->body.c_str());
+        }
+        finished = 1;
+    });
+    */
+}
+
+static void test_axios() {
+    const char* strReq = R"(
+    {
+        "method": "POST",
+        "url": "http://127.0.0.1:8080/echo",
+        "timeout": 10,
+        "params": {
+            "page_no": "1",
+            "page_size": "10"
+        },
+        "headers": {
+            "Content-Type": "application/json"
+        },
+        "body": {
+            "app_id": "123456",
+            "app_secret": "abcdefg"
+        }
+    }
+    )";
+
+    // sync
+    auto resp = axios::axios(strReq);
+    // auto resp = axios::post("http://127.0.0.1:8080/echo", strReq);
+    if (resp == NULL) {
+        printf("request failed!\n");
+    } else {
+        printf("%d %s\r\n", resp->status_code, resp->status_message());
+        printf("%s\n", resp->body.c_str());
+    }
+
+    // async
+    /*
+    int finished = 0;
+    axios::axios(strReq, [&finished](const HttpResponsePtr& resp) {
+        if (resp == NULL) {
+            printf("request failed!\n");
+        } else {
+            printf("%d %s\r\n", resp->status_code, resp->status_message());
+            printf("%s\n", resp->body.c_str());
+        }
+        finished = 1;
+    });
+    */
 }
 
 int main(int argc, char* argv[]) {
@@ -81,8 +155,9 @@ int main(int argc, char* argv[]) {
 
         test_http_sync_client(sync_client);
 
-        // like python requests
         test_requests();
+
+        test_axios();
     }
 
     http_client_del(sync_client);

+ 4 - 2
http/HttpMessage.cpp

@@ -521,7 +521,8 @@ std::string HttpRequest::Dump(bool is_dump_headers, bool is_dump_body) {
     str.reserve(MAX(512, path.size() + 128));
     // GET / HTTP/1.1\r\n
     str = asprintf("%s %s HTTP/%d.%d\r\n",
-            http_method_str(method), path.c_str(), http_major, http_minor);
+            http_method_str(method), path.c_str(),
+            (int)http_major, (int)http_minor);
     if (is_dump_headers) {
         // Host:
         if (headers.find("Host") == headers.end()) {
@@ -549,7 +550,8 @@ std::string HttpResponse::Dump(bool is_dump_headers, bool is_dump_body) {
     str.reserve(512);
     // HTTP/1.1 200 OK\r\n
     snprintf(c_str, sizeof(c_str), "HTTP/%d.%d %d %s\r\n",
-            http_major, http_minor, status_code, http_status_str(status_code));
+            (int)http_major, (int)http_minor,
+            (int)status_code, http_status_str(status_code));
     str = c_str;
     if (is_dump_headers) {
         if (*s_date) {

+ 192 - 0
http/client/axios.h

@@ -0,0 +1,192 @@
+#ifndef HV_AXIOS_H_
+
+#include "json.hpp"
+#include "requests.h"
+
+/*
+ * Inspired by js axios
+ *
+ * @code
+
+#include "axios.h"
+
+int main() {
+    const char* strReq = R"(
+    {
+        "method": "POST",
+        "url": "http://127.0.0.1:8080/echo",
+        "timeout": 10,
+        "params": {
+            "page_no": "1",
+            "page_size": "10"
+        },
+        "headers": {
+            "Content-Type": "application/json"
+        },
+        "body": {
+            "app_id": "123456",
+            "app_secret": "abcdefg"
+        }
+    }
+    )";
+
+    // sync
+    auto resp = axios::axios(strReq);
+    if (resp == NULL) {
+        printf("request failed!\n");
+    } else {
+        printf("%s\n", resp->body.c_str());
+    }
+
+    // async
+    int finished = 0;
+    axios::axios(strReq, [&finished](const HttpResponsePtr& resp) {
+        if (resp == NULL) {
+            printf("request failed!\n");
+        } else {
+            printf("%s\n", resp->body.c_str());
+        }
+        finished = 1;
+    });
+
+    // wait async finished
+    while (!finished) hv_sleep(1);
+    return 0;
+}
+
+**/
+
+using nlohmann::json;
+using requests::Request;
+using requests::Response;
+using requests::ResponseCallback;
+
+namespace axios {
+
+HV_INLINE Request newRequestFromJson(const json& jreq) {
+    Request req(new HttpRequest);
+    // url
+    if (jreq.contains("url")) {
+        req->url = jreq["url"];
+    }
+    // params
+    if (jreq.contains("params")) {
+        req->query_params = jreq["params"].get<QueryParams>();
+    }
+    // headers
+    if (jreq.contains("headers")) {
+        req->headers = jreq["headers"].get<http_headers>();
+    }
+    // body/data
+    const char* body_field = nullptr;
+    if (jreq.contains("body")) {
+        body_field = "body";
+    } else if (jreq.contains("data")) {
+        body_field = "data";
+    }
+    if (body_field) {
+        const json& jbody = jreq[body_field];
+        if (jbody.is_object() || jbody.is_array()) {
+            req->json = jbody;
+        } else if (jbody.is_string()) {
+            req->body = jbody;
+        }
+    }
+    // method
+    if (jreq.contains("method")) {
+        std::string method = jreq["method"];
+        req->method = http_method_enum(method.c_str());
+    } else if (body_field) {
+        req->method = HTTP_POST;
+    } else {
+        req->method = HTTP_GET;
+    }
+    // timeout
+    if (jreq.contains("timeout")) {
+        req->timeout = jreq["timeout"];
+    }
+    return req;
+}
+
+HV_INLINE Request newRequestFromJsonString(const char* req_str) {
+    return newRequestFromJson(json::parse(req_str));
+}
+
+// sync
+HV_INLINE Response axios(const json& jreq, http_method method = HTTP_GET, const char* url = nullptr) {
+    auto req = newRequestFromJson(jreq);
+    if (method != HTTP_GET) {
+        req->method = method;
+    }
+    if (url) {
+        req->url = url;
+    }
+    return req ? requests::request(req) : nullptr;
+}
+
+HV_INLINE Response axios(const char* req_str, http_method method = HTTP_GET, const char* url = nullptr) {
+    return req_str  ? axios(json::parse(req_str), method, url)
+                    : requests::request(method, url);
+}
+
+HV_INLINE Response head(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_HEAD, url);
+}
+
+HV_INLINE Response head(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_HEAD, url);
+}
+
+HV_INLINE Response get(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_GET, url);
+}
+
+HV_INLINE Response get(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_GET, url);
+}
+
+HV_INLINE Response post(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_POST, url);
+}
+
+HV_INLINE Response post(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_POST, url);
+}
+
+HV_INLINE Response put(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_PUT, url);
+}
+
+HV_INLINE Response put(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_PUT, url);
+}
+
+HV_INLINE Response patch(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_PATCH, url);
+}
+
+HV_INLINE Response patch(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_PATCH, url);
+}
+
+HV_INLINE Response Delete(const char* url, const json& jreq) {
+    return axios(jreq, HTTP_DELETE, url);
+}
+
+HV_INLINE Response Delete(const char* url, const char* req_str = nullptr) {
+    return axios(req_str, HTTP_DELETE, url);
+}
+
+// async
+HV_INLINE int axios(const json& jreq, ResponseCallback resp_cb) {
+    auto req = newRequestFromJson(jreq);
+    return req ? requests::async(req, resp_cb) : -1;
+}
+
+HV_INLINE int axios(const char* req_str, ResponseCallback resp_cb) {
+    return axios(json::parse(req_str), resp_cb);
+}
+
+}
+
+#endif // HV_AXIOS_H_

+ 10 - 14
http/client/requests.h

@@ -2,14 +2,14 @@
 #define HV_REQUESTS_H_
 
 /*
- * Imitate python requests api
+ * Inspired by python requests
  *
  * @code
 
 #include "requests.h"
 
 int main() {
-    auto resp = requests::get("/ping");
+    auto resp = requests::get("http://127.0.0.1:8080/ping");
     if (resp == NULL) {
         printf("request failed!\n");
     } else {
@@ -17,12 +17,12 @@ int main() {
         printf("%s\n", resp->body.c_str());
     }
 
-    auto resp2 = requests::post("/echo", "hello,world!");
-    if (resp2 == NULL) {
+    resp = requests::post("http://127.0.0.1:8080/echo", "hello,world!");
+    if (resp == NULL) {
         printf("request failed!\n");
     } else {
-        printf("%d %s\r\n", resp2->status_code, resp2->status_message());
-        printf("%s\n", resp2->body.c_str());
+        printf("%d %s\r\n", resp->status_code, resp->status_message());
+        printf("%s\n", resp->body.c_str());
     }
 
     return 0;
@@ -61,18 +61,14 @@ HV_INLINE Response request(http_method method, const char* url, const http_body&
     return request(req);
 }
 
-HV_INLINE Response get(const char* url, const http_headers& headers = DefaultHeaders) {
-    return request(HTTP_GET, url, NoBody, headers);
-}
-
-HV_INLINE Response options(const char* url, const http_headers& headers = DefaultHeaders) {
-    return request(HTTP_OPTIONS, url, NoBody, headers);
-}
-
 HV_INLINE Response head(const char* url, const http_headers& headers = DefaultHeaders) {
     return request(HTTP_HEAD, url, NoBody, headers);
 }
 
+HV_INLINE Response get(const char* url, const http_headers& headers = DefaultHeaders) {
+    return request(HTTP_GET, url, NoBody, headers);
+}
+
 HV_INLINE Response post(const char* url, const http_body& body = NoBody, const http_headers& headers = DefaultHeaders) {
     return request(HTTP_POST, url, body, headers);
 }