【问题标题】:accepting Uri between 2 numbers接受两个数字之间的 Uri
【发布时间】:2021-12-13 12:42:38
【问题描述】:

我正在通过 Visual Studio Code 开发 ESP-idf。目前我正在开发一个网络服务器实现,我想接受以下网址:

IPADDRESS/command/on/5(1 到 32 之间的数字)

最简单(但不是很有效)的解决方案是,像这样初始化每个 uri

static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/1",
    .method    = HTTP_POST,
    .handler   = on_command_handler

};
static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/2",
    .method    = HTTP_POST,
    .handler   = on_command_handler

};

等等。

但是不应该有更简单的方法吗? 提前致谢!

问候

编辑: 好吧,我不知道它是怎么发生的,但我的整个项目现在已经消失了。

我尝试重做我的步骤,但遇到了一个我很确定上次不存在的新问题。

当我尝试添加这一行时:

    conf.uri_match_fn = httpd_uri_match_wildcard;

我收到以下错误消息:

错误:“httpd_ssl_config_t”{又名“struct httpd_ssl_config”}没有名为“uri_to_match”的成员
conf.uri_to_match = httpd_uri_match_wildcard;

我不知道为什么会突然出现,但我真的不知道我与上次插入此行时所做的不同。

我的 main.c 文件现在看起来像这样:


   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <esp_wifi.h>
#include <esp_event.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include "esp_netif.h"
#include "esp_eth.h"
#include "protocol_examples_common.h"

#include <esp_https_server.h>

/* A simple example that demonstrates how to create GET and POST
 * handlers and start an HTTPS server.
*/

static const char *TAG = "example";


/* An HTTP GET handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;
}

static esp_err_t status_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static esp_err_t command_on_post_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static esp_err_t command_off_post_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;

}

static const httpd_uri_t getStatus = {
    .uri       = "/status",
    .method    = HTTP_GET,
    .handler   = status_get_handler
};

static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/*",
    .method    = HTTP_POST,
    .handler   = command_on_post_handler
};

static const httpd_uri_t postCommandOff = {
    .uri       = "/command/off/*",
    .method    = HTTP_POST,
    .handler   = command_off_post_handler
};

static const httpd_uri_t root = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = root_get_handler
};


static httpd_handle_t start_webserver(void)
{
    httpd_handle_t server = NULL;

    // Start the httpd server
    ESP_LOGI(TAG, "Starting server");

    httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();

    extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start");
    extern const unsigned char cacert_pem_end[]   asm("_binary_cacert_pem_end");
    conf.cacert_pem = cacert_pem_start;
    conf.cacert_len = cacert_pem_end - cacert_pem_start;

    extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start");
    extern const unsigned char prvtkey_pem_end[]   asm("_binary_prvtkey_pem_end");
    conf.prvtkey_pem = prvtkey_pem_start;
    conf.prvtkey_len = prvtkey_pem_end - prvtkey_pem_start;

    //////////////////////////////////////////////////////////
    //////////this line causes the problem///////////////////
    conf.uri_match_fn = httpd_uri_match_wildcard;

    esp_err_t ret = httpd_ssl_start(&server, &conf);
    if (ESP_OK != ret) {
        ESP_LOGI(TAG, "Error starting server!");
        return NULL;
    }

    // Set URI handlers
    ESP_LOGI(TAG, "Registering URI handlers");
    httpd_register_uri_handler(server, &root);
    httpd_register_uri_handler(server, &getStatus);
    httpd_register_uri_handler(server, &postCommandOff);
    httpd_register_uri_handler(server, &postCommandOn);
    return server;
}

static void stop_webserver(httpd_handle_t server)
{
    // Stop the httpd server
    httpd_ssl_stop(server);
}

static void disconnect_handler(void* arg, esp_event_base_t event_base,
                               int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server) {
        stop_webserver(*server);
        *server = NULL;
    }
}

static void connect_handler(void* arg, esp_event_base_t event_base,
                            int32_t event_id, void* event_data)
{
    httpd_handle_t* server = (httpd_handle_t*) arg;
    if (*server == NULL) {
        *server = start_webserver();
    }
}

void app_main(void)
{
    static httpd_handle_t server = NULL;

    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* Register event handlers to start server when Wi-Fi or Ethernet is connected,
     * and stop server when disconnection happens.
     */

#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());
}

EDIT2:

我尝试了以下方法: 在头文件 esp_https_server.h conf 中定义如下 =

    .httpd = {                                    \
        .task_priority      = tskIDLE_PRIORITY+5, \
        .stack_size         = 10240,              \
        .core_id            = tskNO_AFFINITY,     \
        .server_port        = 0,                  \
        .ctrl_port          = 32768,              \
        .max_open_sockets   = 4,                  \
        .max_uri_handlers   = 8,                  \
        .max_resp_headers   = 8,                  \
        .backlog_conn       = 5,                  \
        .lru_purge_enable   = true,               \
        .recv_wait_timeout  = 5,                  \
        .send_wait_timeout  = 5,                  \
        .global_user_ctx = NULL,                  \
        .global_user_ctx_free_fn = NULL,          \
        .global_transport_ctx = NULL,             \
        .global_transport_ctx_free_fn = NULL,     \
        .open_fn = NULL,                          \
        .close_fn = NULL,                         \
        .uri_match_fn = NULL                      \ //this is the part which is "no member"
    },                                            \
    .cacert_pem = NULL,                           \
    .cacert_len = 0,                              \
    .client_verify_cert_pem = NULL,               \
    .client_verify_cert_len = 0,                  \
    .prvtkey_pem = NULL,                          \
    .prvtkey_len = 0,                             \
    .transport_mode = HTTPD_SSL_TRANSPORT_SECURE, \
    .port_secure = 443,                           \
    .port_insecure = 80,                          \
}

您可以清楚地看到,.uri_match_fn 设置为 NULL(因此它是该结构的成员)。如果我在标题中设置 .uri_match_fn = httpd_uri_match_wildcard \ 它确实有效,但我不想更改默认设置功能。我可以添加另一个实现 uri 通配符的函数,但我认为问题出在其他地方。

有人可能有一个想法,为什么会这样?

【问题讨论】:

  • 如果 URL 路由器不支持正则表达式或通配符 ([2-8]),您必须在处理程序中实现它并路由 /command/on,如果 URL 非法则返回 404
  • 好吧,我认为不支持正则表达式或通配符。你的意思是在处理程序中实现它,我应该解析传入的非法 uri 和路由,以防它采用我想要的格式?
  • 如果 uri 匹配是前缀匹配(他们没有在文档中说明,请尝试 uri="/command/on/"),在处理程序中检查 @987654328 之后的数字@ 有效,如果没有设置响应404 并退出
  • 我想我开始理解你的方法了。但是,如果我在“/on/”之后添加一个数字(例如 /on/6),我将无法访问我的处理程序,因为我得到响应“找不到 url”。

标签: https webserver esp-idf


【解决方案1】:

经过搜索,我找到了一个示例,说明了它是如何使用的:

您必须将 URI 匹配器设置为通配符匹配。

config.uri_match_fn = httpd_uri_match_wildcard;

static esp_err_t on_command_handler(httpd_req_t *req)
{
    // req->uri is character array with request uri
    // find the number after /on/ and validate
    // and call httpd_resp_send_404(req)
    return ESP_OK;
}

static const httpd_uri_t postCommandOn = {
    .uri       = "/command/on/*",
    .method    = HTTP_POST,
    .handler   = on_command_handler
};

httpd_register_uri_handler(server_handle, &postCommandOn);

【讨论】:

  • 啊。这就是我滑入命令/打开/处理程序的方式。好的,现在我明白了。我想从现在开始我应该没事了。谢谢!!
  • @Dansen 如果你有一点空闲,你可以编写一个支持正则表达式的 URI 匹配器,或者有人已经这样做了
  • 一旦我完成了我的项目,我可能会想要这样做。我有点想深入了解 esp idf。
【解决方案2】:

ISP IDF HTTP 服务器支持custom URI matchers,您可以在其中创建自己的逻辑来匹配传入的请求 URI 或使用basic wildcard expressions。我没有时间深入研究生成示例代码的 API 文档,但它看起来相当简单。

【讨论】:

  • 如何使用配置中的httpd_uri_match_func_t不是很清楚,文字很模糊。 OP 没有使用 *,? 通配符,它​​们不支持字符类 []
  • @Tarmo 哦,好吧,这对我帮助很大!现在我用命令/打开/(我想要的任何东西)接受每个 uri,现在我想过滤那些东西。遗憾的是,由于字符限制,我无法在此处添加函数 httpd_uri_match_wildcard。我对所有这些东西有点陌生,我不确定我应该在函数中编辑哪个部分。你可能有一些建议?
  • gyazo.com/1168ccc98953c3d517f973e24eb1d3ac gyazo.com/ea46f326a7194c125feb173648a8bf41 有截图。不确定您是否真的可以使用ist。但是,是的......它可能会有所帮助
  • @rioV8 - 由于资源限制,嵌入式系统通常避免使用正则表达式。为了匹配非常简单的模式,例如这个(数字 1-32),您可以使用基本的字符串标记化和字符串到整数的转换。
猜你喜欢
  • 1970-01-01
  • 2020-08-05
  • 1970-01-01
  • 2016-10-15
  • 2013-08-06
  • 2021-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多