HTTPC library HTTP client library based on the INTERNAL implementation of the CF framework socket.

The HTTPC library has built-in SSL support to request third-party interfaces without using a proxy.

HTTPC supports header, args, body, timeout request Settings, perfect support for various HTTPC invocation methods.

The API is introduced

Before using HTTPC library, manually import HTTPC library: Local HTTPC = require “HTTPC “.

httpc.get(domain, HEADER, ARGS, TIMEOUT)

Calling the GET method makes an HTTP GET request to the domain.

Domain is a string that conforms to the URL definition specification.

A HEADER is a key-value array that is used to add custom headers.

ARGS is a key-value array of request parameters. For GET methods, it is automatically formatted as ARGS [n][1]= ARGS [n][2]& ARGS [n+1][1]= ARGS [n+1][2];

TIMEOUT is the maximum TIMEOUT time of an HTTPC request.

httpc.post(domain, HEADER, BODY, TIMEOUT)

Calling the POST method will make an HTTP POST request to the domain, and the content-type of this method will be set to: Application/X-www-form-urlencoded.

Domain is a string that conforms to the URL definition specification.

A HEADER is a key-value array that is used to add custom headers. Content-type and Content-Length Settings are not supported.

BODY is a key-value array that is automatically formatted as: BODY [n][1]= BODY [n][2]& BODY [n+1][1]= BODY [n+1][2];

TIMEOUT is the maximum TIMEOUT time of an HTTPC request.

httpc.json(domain, HEADER, JSON, TIMEOUT)

The JSON method will make an HTTP POST request to the domain. The content-type of this method is set to application/json.

A HEADER is a key-value array that is used to add custom headers. Content-type and Content-Length Settings are not supported.

JSON must be a string;

TIMEOUT is the maximum TIMEOUT time of an HTTPC request.

httpc.file(domain, HEADER, FILES, TIMEOUT)

The file method will make an HTTP POST request to the domain.

A HEADER is a key-value array that is used to add custom headers. Content-type and Content-Length Settings are not supported.

FILES is a key-value array. Each item contains attributes such as name, filename, file, type, and so on. This parameter is optional.

TIMEOUT is the maximum TIMEOUT time of an HTTPC request.

HTTPC return value

All HTTPC request interfaces return two values: code, response. code: indicates the HTTP status code, and response: indicates the response body(a string).

The argument is not correct, the connection is broken or something else is wrong, code is going to be nil, response is an error message.

“One-time HTTP request”

What is a one-time HTTPC request?

Every time we use the HTTPC library to request a third-party HTTP interface, we close the connection when the interface returns. This is not a problem in everyday use.

However, when we need to request the same interface multiple times, it is not efficient to close the connection after each request, so let’s try using an HTTP class object to solve this problem.

Note: HTTPC class objects cannot use the same connection for interfaces of different domains, which returns an error call to the user.

HTTPC library class object usage introduction

To use HTTPC class, import the HTTPC class library as follows: Local HTTPC = require “httpc.class”.

To initiate requests using HTTPC, you need to create an HTTPC object, for example, Local hc = HTTPC :new {}. After HTTPC objects are created and initialized, use the same method as described in the preceding API.

Hc has the same API as HTTPC, but requires a different invocation. For example, hc:get, HC: POST, hc:json, and hc:file.

Once thehcWhen finished, the call needs to be displayedhc:close()Method to close the created HTTPC object and destroy the HTTPC connection.

Began to practice

Now, let’s put the API usage we learned above into practice.

1. Start a Web server with an HTTPD library

Start an HTTPD server in main.lua.

local httpd = require "httpd"
local json = require "json"

local app = httpd:new("httpd")


app:listen("".8080)

app:run()
Copy the code

1. Add an API route to query the IP address

We use HTTPD library to start a server service, and external IP address query interface

app:api('/ip'.function(content)
	local httpc = require "httpc"
	local args = content.args
	if not args or not args['ip'] then
		return json.encode({
			code = 400,
			msg = "Wrong way to call an interface",
			data = json.null,
			})
	end
	local code, response = httpc.get("http://freeapi.ipip.net/"..args["ip"])
	if code ~= 200 then
		return json.encode({
			code = 401,
			msg = "Failed to obtain data",
			data = json.null,
			})
	end
	return response
end)
Copy the code

The code is now complete! Let’s open a browser and enter: http://localhost:8090/ip? IP =8.8.8.8 Viewing returned data.

2. Query the owning places of multiple IP addresses

One response to one request is the nature of the HTTP protocol! However, we often encounter a batch request business scenario, so let’s design a batch request/return example.

Let’s assume that the client will send a POST request with a json body containing an IP array: ip_list = {1.1.1.1, 8.8.8.8, 114.114.114.114}.

After receiving the array, the server needs to return the IP address information to the client once.

app:api('/ips'.function(content)
	local httpc = require "httpc.class"
	if not content.json then
		return json.encode({
			code = 400,
			msg  = "Wrong call parameter",
			data = json.null,
		})
	end
	local args = json.decode(content.body)
	if type(args) ~= 'table' or type(args['ip_list']) ~ ='table' then
		return json.encode({
			code = 400,
			msg  = "Wrong parameter type",
			data = json.null,
		})
	end
	local hc = httpc:new {}
	local ret = { code = 200 , data = {}}
	for _, ip in ipairs(args['ip_list']) do
		local code, response = hc:get("http://freeapi.ipip.net/"..ip)
		ret['data'][#ret['data'] +1] = json.decode(response)
	end
	return json.encode(ret)
end)
Copy the code

Because normal browser POST cannot send JSON, let’s use the curl command line tool to test:

curl -H "Content-Type: application/json" -X POST -d '{" ip_list ": [" 1.1.1.1", "8.8.8.8", "114.114.114.114"]}' http://localhost:8090/ip
Copy the code

The following data is returned:

{"code":200."data": [["CLOUDFLARE.COM"."CLOUDFLARE.COM".""."".""], ["GOOGLE.COM"."GOOGLE.COM"."".""."level3.com"], ["114DNS.COM"."114DNS.COM".""."".""]]}
Copy the code

3. Keep optimizing.

The above example seems perfect enough! We made three requests using keepalive, which reduced the connection cost of the request by 50% (TCP handshake).

But for those of us who really need performance, the idea that each request needs to wait until the last one has been processed before a new request can be made is obviously not enough.

In such cases, the HTTPC library provides a method called multi_request. The specific method of use is here.

This method allows us to send dozens or hundreds of requests simultaneously to resolve the problem of a single connection blocking.

4. Concurrent requests

Now, let me use the HTTPC library’s multi_request method to request multiple interfaces concurrently to reduce the problem of connection blocking.

app:api('/ips_multi'.function (content)
	local httpc = require "httpc"
	if not content.json then
		return json.encode({
			code = 400,
			msg  = "Wrong call parameter",
			data = json.null,
		})
	end
	local args = json.decode(content.body)
	if type(args) ~= 'table' or type(args['ip_list']) ~ ='table' then
		return json.encode({
			code = 400,
			msg  = "Wrong parameter type",
			data = json.null,
		})
	end
	local requests = {}
	local responses = { code = 200, data = {}}
	for _, ip in ipairs(args["ip_list"]) do
		requests[#requests+1] = {
			domain = "http://freeapi.ipip.net/"..ip,
			method = "get",
		}
	end
	local ok, ret = httpc.multi_request(requests)
	for _, res in ipairs(ret) do
		responses['data'] [#responses['data'] + 1] = res
	end
	return json.encode(responses)
end)
Copy the code

Curl: curl curl: curl curl: curl curl: curl curl

curl -H "Content-Type: application/json" -X POST -d '{" ip_list ": [" 1.1.1.1", "8.8.8.8", "114.114.114.114"]}' http://localhost:8090/ips_multi
Copy the code

We can see from cf’s request response time that the response time consumption is again reduced by 50%.

[candy@MacBookPro:~/Documents/ Core_framework] $./cfadmin [2019/06/16 17:45:21] 0.0.0.0:8090 [2019/06/16 17:45:21] [INFO] HTTPD is running a Web Server... [2019/06/16 17:45:23] - ::1 - ::1 - /ips_multi - POST - 200 - req_time: 0.140253/Sec [2019/06/16 17:45:38] - ::1 - :1 - / IPS-post-200-req_time: 0.288286/SecCopy the code

Complete code

local httpd = require "httpd"
local json = require "json"

local app = httpd:new("httpd")

app:api('/ip'.function(content)
	local httpc = require "httpc"
	local args = content.args
	if not args or not args['ip'] then
		return json.encode({
			code = 400,
			msg = "Wrong way to call an interface",
			data = json.null,
			})
	end
	local code, response = httpc.get("http://freeapi.ipip.net/"..args["ip"])
	if code ~= 200 then
		return json.encode({
			code = 401,
			msg = "Failed to obtain data",
			data = json.null,
			})
	end
	return response
end)

app:api('/ips'.function(content)
	local httpc = require "httpc.class"
	if not content.json then
		return json.encode({
			code = 400,
			msg  = "Wrong call parameter",
			data = json.null,
		})
	end
	local args = json.decode(content.body)
	if type(args) ~= 'table' or type(args['ip_list']) ~ ='table' then
		return json.encode({
			code = 400,
			msg  = "Wrong parameter type",
			data = json.null,
		})
	end
	local hc = httpc:new {}
	local ret = { code = 200 , data = {}}
	for _, ip in ipairs(args['ip_list']) do
		local code, response = hc:get("http://freeapi.ipip.net/"..ip)
		ret['data'][#ret['data'] +1] = json.decode(response)
	end
	return json.encode(ret)
end)

app:api('/ips_multi'.function (content)
	local httpc = require "httpc"
	if not content.json then
		return json.encode({
			code = 400,
			msg  = "Wrong call parameter",
			data = json.null,
		})
	end
	local args = json.decode(content.body)
	if type(args) ~= 'table' or type(args['ip_list']) ~ ='table' then
		return json.encode({
			code = 400,
			msg  = "Wrong parameter type",
			data = json.null,
		})
	end
	local requests = {}
	local responses = { code = 200, data = {}}
	for _, ip in ipairs(args["ip_list"]) do
		requests[#requests+1] = {
			domain = "http://freeapi.ipip.net/"..ip,
			method = "get",}end
	local ok, ret = httpc.multi_request(requests)
	for _, res in ipairs(ret) do
		responses['data'][#responses['data'] + 1] = res
	end
	return json.encode(responses)
end)

app:listen("".8090)

app:run()
Copy the code

Continue to learn

In the next section we’ll learn how to write webSockets using the HTTPD library.