[英]Arduino with WiFi Shield make weird post request
I am working on small weather station based on Arduino Uno. 我正在基于Arduino Uno的小型气象站上工作。 In fact I am already create prototype which measure humidity, temperature, pressure and level of CO2 and send data trough POST request to server. 实际上,我已经创建了一个原型,该原型可以测量湿度,温度,压力和CO2的水平,并通过POST请求将数据发送到服务器。 For the whole week it works perfectly sending data to server on hourly basis. 在整个星期中,它每小时都可以完美地将数据发送到服务器。 But yesterday I find out that no new data coming. 但是昨天我发现没有新数据到来。 My first thought was that something wrong with WiFi, I restart router, check connectivity, everything work perfect. 我的第一个想法是WiFi出现问题,我重新启动路由器,检查连接性,一切正常。 I think if something wrong with Arduino and restart it, it works. 我认为,如果Arduino有问题并重新启动它,则可以正常工作。 So I check what I get after connection and answer was: 所以我检查连接后得到的答案是:
HTTP/1.1 405 METHOD NOT ALLOWED
Date: Fri, 02 Sep 2016 13:27:02 GMT
Server: Apache/2.4.10 (Debian)
Allow: GET, OPTIONS, POST, HEAD
Content-Length: 178
Connection: close
Content-Type: text/html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
*CLOS*
Ok then I send POST request to server manually (trough Postman) and it is works. 好的,然后我手动将POST请求发送到服务器(通过Postman),它是可行的。 So I go to server and start read logs, there is no errors but in access.log I find out something interesting: 因此,我进入服务器并开始读取日志,没有任何错误,但是在access.log中我发现了一些有趣的东西:
Working post request coming from Postman look like: 来自邮递员的工作职位要求如下:
15.15.119.103 - - [02/Sep/2016:13:54:03 +0300] "POST /api/meteo HTTP/1.1" 200 319 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"
But when it comes from Arduino it look in strange way 但是当它来自Arduino时,它看起来很奇怪
15.15.119.103 - - [02/Sep/2016:13:53:54 +0300] "*HELLO*POST /api/meteo HTTP/1.1" 405 380 "-" "-"
So as you can see it comes to server not like POST but LIKE " HELLO POST" and it is ruined everything. 因此,如您所见,它不像POST那样涉及服务器,而是像“ HELLO POST”那样,它毁了一切。 The problem is that I change nothing in my code and it is working somehow during the week. 问题是我在代码中没有进行任何更改,并且在一周中以某种方式工作。 You can see peace of my Arduino code bellow: 您可以在下面看到我的Arduino代码的平静:
#include <WiFly.h>
#include "HTTPClient.h"
#define SSID "bbbbbbb"
#define KEY "ccccccc"
#define AUTH WIFLY_AUTH_WPA2_PSK
#define HTTP_POST_URL "15.15.25.67/api/meteo"
SoftwareSerial uart(2, 3);
WiFly wifly(uart);
HTTPClient http;
String PostData;
char PostBuf[90];
uart.begin(9600);
// check if WiFly is associated with AP(SSID)
if (!wifly.isAssociated(SSID)) {
while (!wifly.join(SSID, KEY, AUTH)) {
Serial.println("Failed to join " SSID);
Serial.println("Wait 0.1 second and try again...");
delay(100);
}
wifly.save(); // save configuration,
}
PostData.toCharArray(PostBuf, 90);
while (http.post(HTTP_POST_URL, PostBuf, 10000) < 0) {
}
while (wifly.receive((uint8_t *)&get, 1, 1000) == 1) {
Serial.print(get);
}
uart.end();
So it connect to WiFI and send request, but type of request is quite strange. 因此它连接到WiFI并发送请求,但是请求的类型很奇怪。 I try to find any key which can help with no results maybe somebody can give me advise? 我试图找到没有任何帮助的键,也许有人可以给我建议?
In case if needed I put here HTTPClient.h: 如果需要,我将HTTPClient.h放在这里:
#ifndef __HTTP_CLIENT_H__
#define __HTTP_CLIENT_H__
#define HTTP_CLIENT_DEFAULT_TIMEOUT 30000 // 3s
#define HTTP_MAX_HOST_LEN 20
#define HTTP_MAX_PATH_LEN 64
#define HTTP_MAX_BUF_LEN 100
#define HTTP_DEFAULT_PORT 80
#include <Arduino.h>
#include <WiFly.h>
class HTTPClient {
public:
HTTPClient();
int get(const char *url, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
int get(const char *url, const char *header, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
int post(const char *url, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
int post(const char *url, const char *headers, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
private:
int parseURL(const char *url, char *host, int max_host_len, uint16_t *port, char *path, int max_path_len);
int connect(const char *url, const char *method, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
int connect(const char *url, const char *method, const char *header, const char *data, int timeout = HTTP_CLIENT_DEFAULT_TIMEOUT);
WiFly* wifly;
};
#endif // __HTTP_CLIENT_H__
As for HTTPClient.cpp it looks like this: 对于HTTPClient.cpp,它看起来像这样:
#include <string.h>
#include "HTTPClient.h"
#include "Debug.h"
HTTPClient::HTTPClient()
{
wifly = WiFly::getInstance();
}
int HTTPClient::get(const char *url, int timeout)
{
return connect(url, "GET", NULL, NULL, timeout);
}
int HTTPClient::get(const char *url, const char *headers, int timeout)
{
return connect(url, "GET", headers, NULL, timeout);
}
int HTTPClient::post(const char *url, const char *data, int timeout)
{
return connect(url, "POST", NULL, data, timeout);
}
int HTTPClient::post(const char *url, const char *headers, const char *data, int timeout)
{
return connect(url, "POST", headers, data, timeout);
}
int HTTPClient::connect(const char *url, const char *method, const char *data, int timeout)
{
return connect(url, method, NULL, data, timeout);
}
int HTTPClient::connect(const char *url, const char *method, const char *headers, const char *data, int timeout)
{
char host[HTTP_MAX_HOST_LEN];
uint16_t port;
char path[HTTP_MAX_PATH_LEN];
if (parseURL(url, host, sizeof(host), &port, path, sizeof(path)) != 0) {
DBG("Failed to parse URL.\r\n");
return -1;
}
if (!wifly->connect(host, port, timeout)) {
DBG("Failed to connect.\r\n");
return -2;
}
// Send request
char buf[HTTP_MAX_BUF_LEN];
snprintf(buf, sizeof(buf), "%s %s HTTP/1.1\r\n", method, path);
wifly->send(buf);
// Send all headers
snprintf(buf, sizeof(buf), "Host: %s\r\nConnection: close\r\n", host);
wifly->send(buf);
if (data != NULL) {
snprintf(buf, sizeof(buf), "Content-Length: %d\r\nContent-Type: text/plain\r\n", strlen(data));
wifly->send(buf);
}
if (headers != NULL) {
wifly->send(headers);
}
// Close headers
wifly->send("\r\n");
// Send body
if (data != NULL) {
wifly->send(data);
}
return 0;
}
int HTTPClient::parseURL(const char *url, char *host, int max_host_len, uint16_t *port, char *path, int max_path_len)
{
char *scheme_ptr = (char *)url;
char *host_ptr = (char *)strstr(url, "://");
if (host_ptr != NULL) {
if (strncmp(scheme_ptr, "http://", 7)) {
DBG("Bad scheme\r\n");
return -1;
}
host_ptr += 3;
} else {
host_ptr = (char *)url;
}
int host_len = 0;
char *port_ptr = strchr(host_ptr, ':');
if (port_ptr != NULL) {
host_len = port_ptr - host_ptr;
port_ptr++;
if (sscanf(port_ptr, "%hu", port) != 1) {
DBG("Could not find port.\r\n");
return -3;
}
} else {
*port = HTTP_DEFAULT_PORT;
}
char *path_ptr = strchr(host_ptr, '/');
if (host_len == 0) {
host_len = path_ptr - host_ptr;
}
if (max_host_len < (host_len + 1)) {
DBG("Host buffer is too small.\r\n");
return -4;
}
memcpy(host, host_ptr, host_len);
host[host_len] = '\0';
int path_len;
char *fragment_ptr = strchr(host_ptr, '#');
if (fragment_ptr != NULL) {
path_len = fragment_ptr - path_ptr;
} else {
path_len = strlen(path_ptr);
}
if (max_path_len < (path_len + 1)) {
DBG("Path buffer is too small.\r\n");
return -5;
}
memcpy(path, path_ptr, path_len);
path[path_len] = '\0';
return 0;
}
I find out a root of problem, by default WiFiShield v.1.0 say " HELLO " when TCP connection opened. 我发现了问题的根源,默认情况下,当TCP连接打开时,WiFiShield v.1.0会说“ HELLO ”。 In fact it written deep into the manual. 实际上,它已深入手册中。
My connection was not so fast, so it is manage to say " HELLO " before connectivity, but I upgrade router firmware and it start working faster, that is why " HELLO " connected to next request which was POST in this case. 我的连接不是那么快,因此在连接之前可以说“ HELLO ”,但是我升级了路由器固件,它开始工作得更快,这就是为什么“ HELLO ”连接到下一个请求(在这种情况下为POST)的原因。 Solution is simple just add: 解决方法很简单,只需添加:
wifly.sendCommand("set comm remote 0\r");
and this command disable welcome message on WiFiShield. 并且此命令在WiFiShield上禁用欢迎消息。 Hope it helps somebody. 希望它能帮助到别人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.