简体   繁体   English

带有WiFi Shield的Arduino发出奇怪的帖子请求

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM