在 NodeMCU 上使用 API 时仅获取 JSON 的一部分
Get only part of a JSON when using an API on NodeMCU
我正在使用 http.get()
从我正在使用的 API 中获取 JSON,但它没有获取数据。我怀疑这个 JSON 对于 NodeMCU 来说太大了。我只需要子部分 "stats:" 中的信息。是否可以仅 http.get()
JSON 的那一部分?
编辑:
这是我的代码
function getstats()
http.get("https://api.aeon-pool.com/v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit", nil, function(code, pool)
if (code < 0) then
print("can't get stats")
else
h = cjson.decode(pool)
hashrate = h[1]["hashrate"]
print(hashrate)
dofile('update_display.lua')
end
end)
end
我还有另一个函数从 getstats()
上面的另一个 api 获取数据
function getaeonrate()
http.get("https://api.coinmarketcap.com/v1/ticker/aeon/?convert=EUR", nil, function(code, dataaeon)
if (code < 0) then
print("can't get aeon")
else
-- Decode JSON data
m = cjson.decode(dataaeon)
-- Extract AEON/EUR price from decoded JSON
aeonrate = string.format("%f", m[1]["price_eur"]);
aeonchange = "24h " .. m[1]["percent_change_24h"] .. "% 7d " .. m[1]["percent_change_7d"] .. "%"
dofile('update_display.lua')
end
end)
end
但现在奇怪的是,当我想从 getstats() 访问 'pool' 时,我从 getaeonrate() 获得了 json 数据。所以 "hashrate" 甚至不在 json 中,因为我从另一个函数得到 json。
我尝试仅使用 getstats() 创建一个新项目,但它根本不起作用,我总是遇到这样的错误
HTTP client: Disconnected with error: -9
HTTP client: Connection timeout
HTTP client: Connection timeout
昨天我认为 api.aeon-pool.com 的响应太大了,如果你在你的网络浏览器中查看 json 你可以看到顶部条目是 'stats:' 我只需要 none 其他东西。因此,如果请求太大,最好只 http.get() json 的那部分,因此我最初的问题。目前我什至不确定是什么不正常,我读到 nodemcu 固件通常在 http.get() 方面有问题并且很长时间都没有正常工作,但是从 api.coinmarketcap.com 在原始项目中工作正常。
HTTP 模块的问题几乎可以肯定与 https://github.com/nodemcu/nodemcu-firmware/issues/1707 有关(SSL 和 HTTP 有问题)。
因此,我尝试在当前主分支上使用 more bare-bone TLS 模块。这意味着您需要手动解析 HTTP 响应,包括所有 headers 以查找 JSON 内容。此外,您似乎使用的是较旧的 NodeMCU 版本,因为您仍在使用 CJSON - 我在下面使用了 SJSON:
当前NodeMCU主分支
function getstats()
buffer = nil
counter = 0
local srv = tls.createConnection()
srv:on("receive", function(sck, payload)
print("[stats] received data, " .. string.len(payload))
if buffer == nil then
buffer = payload
else
buffer = buffer .. payload
end
counter = counter + 1
-- not getting HTTP content-length header back -> poor man's checking for complete response
if counter == 2 then
print("[stats] done, processing payload")
local beginJsonString = buffer:find("{")
local jsonString = buffer:sub(beginJsonString)
local hashrate = sjson.decode(jsonString)["stats"]["hashrate"]
print("[stats] hashrate from aeon-pool.com: " .. hashrate)
end
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit HTTP/1.1\r\nHost: api.aeon-pool.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.aeon-pool.com")
end
请注意,每个网络帧都会触发接收事件:https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketon
由于 TLS 握手失败,NodeMCU 无法与 api.coinmarketcap.com 建立连接。不知道为什么会这样。否则你的 getaeonrate()
也可以同样实现。
冰雪奇缘1.5.4分支
使用旧分支,网络模块可以连接到 coinmarketcap.com。
function getaeonrate()
local srv = net.createConnection(net.TCP, 1)
srv:on("receive", function(sck, payload)
print("[aeon rate] received data, " .. string.len(payload))
local beginJsonString = payload:find("%[")
local jsonString = payload:sub(beginJsonString)
local json = cjson.decode(jsonString)
local aeonrate = string.format("%f", json[1]["price_eur"]);
local aeonchange = "24h " .. json[1]["percent_change_24h"] .. "% 7d " .. json[1]["percent_change_7d"] .. "%"
print("[aeon rate] aeonrate from coinmarketcap.com: " .. aeonrate)
print("[aeon rate] aeonchange from coinmarketcap.com: " .. aeonchange)
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/ticker/aeon/?convert=EUR HTTP/1.1\r\nHost: api.coinmarketcap.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.coinmarketcap.com")
end
结论
- 由于固件 (1707) 中的错误,HTTP 模块和 TLS 对于您的 API 似乎是 no-go。
- 当前 master 分支的 net/TLS 模块设法连接到 api.aeon-pool.com 但没有连接到 api.coinmarketcap.com.
- 对于旧的和冻结的 1.5.4 分支,情况正好相反。
- 固件和 API 提供商之间可能(也)存在不匹配的密码套装问题。
-> :( 没有那样的乐趣
我正在使用 http.get()
从我正在使用的 API 中获取 JSON,但它没有获取数据。我怀疑这个 JSON 对于 NodeMCU 来说太大了。我只需要子部分 "stats:" 中的信息。是否可以仅 http.get()
JSON 的那一部分?
编辑:
这是我的代码
function getstats()
http.get("https://api.aeon-pool.com/v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit", nil, function(code, pool)
if (code < 0) then
print("can't get stats")
else
h = cjson.decode(pool)
hashrate = h[1]["hashrate"]
print(hashrate)
dofile('update_display.lua')
end
end)
end
我还有另一个函数从 getstats()
上面的另一个 api 获取数据function getaeonrate()
http.get("https://api.coinmarketcap.com/v1/ticker/aeon/?convert=EUR", nil, function(code, dataaeon)
if (code < 0) then
print("can't get aeon")
else
-- Decode JSON data
m = cjson.decode(dataaeon)
-- Extract AEON/EUR price from decoded JSON
aeonrate = string.format("%f", m[1]["price_eur"]);
aeonchange = "24h " .. m[1]["percent_change_24h"] .. "% 7d " .. m[1]["percent_change_7d"] .. "%"
dofile('update_display.lua')
end
end)
end
但现在奇怪的是,当我想从 getstats() 访问 'pool' 时,我从 getaeonrate() 获得了 json 数据。所以 "hashrate" 甚至不在 json 中,因为我从另一个函数得到 json。
我尝试仅使用 getstats() 创建一个新项目,但它根本不起作用,我总是遇到这样的错误
HTTP client: Disconnected with error: -9
HTTP client: Connection timeout
HTTP client: Connection timeout
昨天我认为 api.aeon-pool.com 的响应太大了,如果你在你的网络浏览器中查看 json 你可以看到顶部条目是 'stats:' 我只需要 none 其他东西。因此,如果请求太大,最好只 http.get() json 的那部分,因此我最初的问题。目前我什至不确定是什么不正常,我读到 nodemcu 固件通常在 http.get() 方面有问题并且很长时间都没有正常工作,但是从 api.coinmarketcap.com 在原始项目中工作正常。
HTTP 模块的问题几乎可以肯定与 https://github.com/nodemcu/nodemcu-firmware/issues/1707 有关(SSL 和 HTTP 有问题)。
因此,我尝试在当前主分支上使用 more bare-bone TLS 模块。这意味着您需要手动解析 HTTP 响应,包括所有 headers 以查找 JSON 内容。此外,您似乎使用的是较旧的 NodeMCU 版本,因为您仍在使用 CJSON - 我在下面使用了 SJSON:
当前NodeMCU主分支
function getstats()
buffer = nil
counter = 0
local srv = tls.createConnection()
srv:on("receive", function(sck, payload)
print("[stats] received data, " .. string.len(payload))
if buffer == nil then
buffer = payload
else
buffer = buffer .. payload
end
counter = counter + 1
-- not getting HTTP content-length header back -> poor man's checking for complete response
if counter == 2 then
print("[stats] done, processing payload")
local beginJsonString = buffer:find("{")
local jsonString = buffer:sub(beginJsonString)
local hashrate = sjson.decode(jsonString)["stats"]["hashrate"]
print("[stats] hashrate from aeon-pool.com: " .. hashrate)
end
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/stats_address?address=WmsGUrXTR7sgKmHEqRNLgPLndWKSvjFXcd4soHnaxVjY3aBWW4kncTrRcBJJgUkeGwcHfzuZABk6XK6qAp8VmSci2AyGHcUit HTTP/1.1\r\nHost: api.aeon-pool.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.aeon-pool.com")
end
请注意,每个网络帧都会触发接收事件:https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketon
由于 TLS 握手失败,NodeMCU 无法与 api.coinmarketcap.com 建立连接。不知道为什么会这样。否则你的 getaeonrate()
也可以同样实现。
冰雪奇缘1.5.4分支
使用旧分支,网络模块可以连接到 coinmarketcap.com。
function getaeonrate()
local srv = net.createConnection(net.TCP, 1)
srv:on("receive", function(sck, payload)
print("[aeon rate] received data, " .. string.len(payload))
local beginJsonString = payload:find("%[")
local jsonString = payload:sub(beginJsonString)
local json = cjson.decode(jsonString)
local aeonrate = string.format("%f", json[1]["price_eur"]);
local aeonchange = "24h " .. json[1]["percent_change_24h"] .. "% 7d " .. json[1]["percent_change_7d"] .. "%"
print("[aeon rate] aeonrate from coinmarketcap.com: " .. aeonrate)
print("[aeon rate] aeonchange from coinmarketcap.com: " .. aeonchange)
end)
srv:on("connection", function(sck, c)
sck:send("GET /v1/ticker/aeon/?convert=EUR HTTP/1.1\r\nHost: api.coinmarketcap.com\r\nConnection: close\r\nAccept: */*\r\n\r\n")
end)
srv:connect(443, "api.coinmarketcap.com")
end
结论
- 由于固件 (1707) 中的错误,HTTP 模块和 TLS 对于您的 API 似乎是 no-go。
- 当前 master 分支的 net/TLS 模块设法连接到 api.aeon-pool.com 但没有连接到 api.coinmarketcap.com.
- 对于旧的和冻结的 1.5.4 分支,情况正好相反。
- 固件和 API 提供商之间可能(也)存在不匹配的密码套装问题。
-> :( 没有那样的乐趣