lwip-2.1.3自带的httpd网页服务器使用教程(三)使用CGI获取URL参数(GET类型表单)

news2024/9/22 7:33:48

上一篇:lwip-2.1.3自带的httpd网页服务器使用教程(二)使用SSI动态生成网页部分内容

认识URL参数

在上网的时候,我们经常会见到在网址后面带有?A=B&C=D这样的语法格式。例如:
https://blog.csdn.net/ZLK1214/article/details/129151458?csdn_share_tail={%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22129151458%22%2C%22source%22%3A%22ZLK1214%22}
上面这个网址就带有csdn_share_tail参数,等号后面是参数的值。如果有多个参数的话,中间可用&符号连接。

另外我们也可以把网页中的表单的method属性设为get,表单提交后表单的内容也是以URL参数的方式呈现的。

<form name="form1" method="get">
  <label>
    器件名称:
    <input name="devname" type="text" id="devname" value="STM32">
  </label><br>
  <label>
    器件类型: 
    <select name="devtype" id="devtype">
      <option value="1">单片机芯片</option>
      <option value="2">网络芯片</option>
      <option value="3">音频芯片</option>
    </select>
  </label><br>
  <input type="submit" value="搜索">
</form>

<input type="submit" value="搜索">是表单提交按钮,点击按钮后凡是带有name属性的控件的名称和值都会出现在URL中。
例如,上面的表单提交后,浏览器跳转的网址就是:http://stm32f103ze/info.ssi?devname=STM32&devtype=1。

lwip httpd服务器提供的CGI功能就是用来获取这样的URL参数的。lwip提供的CGI功能分为两种:旧式CGI和新式CGI。

使用旧式CGI功能

旧式CGI的功能比较简单,用http_set_cgi_handlers函数指定一些支持URL参数的网页,经过指定的回调函数处理后,跳转到另一页面上(也可以选择不跳转)。
http_set_cgi_handlers的原型如下。
typedef struct
{
    const char *pcCGIName;
    tCGIHandler pfnCGIHandler;
} tCGI;
void http_set_cgi_handlers(const tCGI *cgis, int num_handlers);
其中,参数cgis为tCGI结构体数组(必须是全局变量,不能是局部变量),参数num_handlers为tCGI结构体数组的大小,可由LWIP_ARRAYSIZE宏计算数组的大小。
tCGI结构体里面的pcCGIName是网页的名称,pfnCGIHandler是处理该网页的URL参数的回调函数。回调函数的原型如下:
const char *XXX(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]);
参数iIndex是当前正在处理的网页在tCGI结构体数组中的下标,那么当前正在处理的网页名称就是“全局数组名[iIndex].pcCGIName”。
iNumParams是URL参数的个数,是pcParam数组和pcValue数组的元素个数。
pcParam数组和pcValue数组分别是参数名列表和对应的参数值的列表。
回调函数的返回值是要跳转的网页名称(浏览器的地址栏上显示的仍然还是跳转前的网页文件名),如果不想跳转到另一网页,可直接返回当前网页名称“全局数组名[iIndex].pcCGIName”。
tCGI结构体的pcCGIName成员(跳转前的页面名称),和pfnCGIHandler回调函数的返回值(要跳转的页面)都可以是虚拟页面,并不是必须要在文件系统上能找得到。

旧式CGI的不足之处是URL参数无法和当前HTTP连接的SSI功能(标签替换功能)直接交互。

示例:使用URL参数控制LED灯的亮灭和数码管的显示

(本节例程名称:cgi_test)
首先,在lwip-2.1.3/apps/http/fs下放入动态网页devctrl.ssi,然后运行makefsdata程序打包。devctrl.ssi的内容如下:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>设备控制页</title>
<style type="text/css">
<!--
body {
	font-family: "Times New Roman", Times, serif;
	background: #666666;
	margin: 0;
	padding: 0;
	text-align: center;
	color: #000000;
}
#container {
	width: 780px;
	background: #FFFFFF;
	margin: 0 auto;
	border: 1px solid #000000;
	text-align: left;
}
#header {
	background: #DDDDDD; 
	padding: 0 10px 0 20px;
}
#header h1 {
	margin: 0;
	padding: 10px 0;
}
#mainContent {
	padding: 30px 20px;
	background: #FFFFFF;
	font-size: 14px;
}
#footer {
	padding: 0 10px;
	background: #DDDDDD;
}
#footer p {
	margin: 0;
	padding: 10px 0;
}
-->
</style>
</head>

<body>
<div id="container">
  <div id="header">
    <h1>设备控制页</h1>
  </div>
  <div id="mainContent">
    <form name="form1" method="get" action="">
      <table width="100%" border="0">
        <tr>
          <td width="30%" align="right">LED1: </td>
          <td align="left">
            <label>
              <input type="radio" name="led1" value="on"<!--#led1_on-->>
              亮
            </label>
            <label>
              <input type="radio" name="led1" value="off"<!--#led1_off-->>
              灭
            </label>
          </td>
        </tr>
        <tr>
          <td align="right">LED2: </td>
          <td align="left">
            <label>
              <input type="radio" name="led2" value="on"<!--#led2_on-->>
              亮
            </label>
            <label>
              <input type="radio" name="led2" value="off"<!--#led2_off-->>
              灭
            </label>
          </td>
        </tr>
        <tr>
          <td align="right">LED3: </td>
          <td align="left">
            <label>
              <input type="radio" name="led3" value="on"<!--#led3_on-->>
              亮
            </label>
            <label>
              <input type="radio" name="led3" value="off"<!--#led3_off-->>
              灭
            </label>
          </td>
        </tr>
        <tr>
          <td align="right"><label for="num">数码管: </label></td>
          <td align="left"><input type="text" name="num" id="num" style="width: 100px" value="<!--#segnum-->"></td>
        </tr>
        <tr>
          <td align="right"></td>
          <td align="left"><input type="submit" value="确定"></td>
        </tr>
      </table>
    </form>
  </div>
  <div id="footer">
    <p><b>当前时间: </b><!--#datetime--></p>
  </div>
</div>
</body>
</html>

修改lwipopts.h里面的HTTPD选项,开启CGI功能和SSI功能:

// 配置HTTPD
#define LWIP_HTTPD_CGI 1
#define LWIP_HTTPD_SSI 1
#define LWIP_HTTPD_SSI_INCLUDE_TAG 0
#define LWIP_HTTPD_SSI_RAW 1

编写test.c文件,其中test_init函数在main函数中调用了httpd_init()之后调用。

#include <lwip/apps/httpd.h>
#include <lwip/def.h>
#include <stm32f1xx.h>
#include <string.h>
#include <time.h>
#include "SegDisplay.h"
#include "test.h"

static float test_num;
static tCGI test_cgis[3];

static const char *test_cgis_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
{
  char *endptr;
  float num;
  int i;
  
  for (i = 0; i < iNumParams; i++)
  {
    if (strcasecmp(pcParam[i], "led1") == 0)
    {
      if (strcasecmp(pcValue[i], "on") == 0)
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_SET);
      else if (strcasecmp(pcValue[i], "off") == 0)
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET);
      else if (strcasecmp(pcValue[i], "toggle") == 0)
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_5);
    }
    else if (strcasecmp(pcParam[i], "led2") == 0)
    {
      if (strcasecmp(pcValue[i], "on") == 0)
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
      else if (strcasecmp(pcValue[i], "off") == 0)
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
      else if (strcasecmp(pcValue[i], "toggle") == 0)
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    }
    else if (strcasecmp(pcParam[i], "led3") == 0)
    {
      if (strcasecmp(pcValue[i], "on") == 0)
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_6, GPIO_PIN_SET);
      else if (strcasecmp(pcValue[i], "off") == 0)
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_6, GPIO_PIN_RESET);
      else if (strcasecmp(pcValue[i], "toggle") == 0)
        HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_6);
    }
    else if (strcasecmp(pcParam[i], "num") == 0)
    {
      num = strtof(pcValue[i], &endptr);
      if (*endptr == '\0')
      {
        test_num = num;
        SegDisplay_SetFloatNumber(num);
      }
    }
  }
  return "/devctrl.ssi";
}

static u16_t test_ssi_handler(const char *ssi_tag_name, char *pcInsert, int iInsertLen)
{
  struct tm tm;
  time_t t;
  
  if (strcmp(ssi_tag_name, "led1_on") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == GPIO_PIN_SET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "led1_off") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == GPIO_PIN_RESET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "led2_on") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "led2_off") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_RESET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "led3_on") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_6) == GPIO_PIN_SET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "led3_off") == 0)
  {
    if (HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_6) == GPIO_PIN_RESET)
      snprintf(pcInsert, iInsertLen, " checked");
    else
      snprintf(pcInsert, iInsertLen, "");
  }
  else if (strcmp(ssi_tag_name, "segnum") == 0)
    snprintf(pcInsert, iInsertLen, "%g", test_num);
  else if (strcmp(ssi_tag_name, "datetime") == 0)
  {
    time(&t);
    localtime_r(&t, &tm);
    strftime(pcInsert, iInsertLen, "%Y-%m-%d %H:%M:%S", &tm);
  }
  else
    return HTTPD_SSI_TAG_UNKNOWN;
  return strlen(pcInsert);
}

static void test_led_init(void)
{
  GPIO_InitTypeDef gpio;
  
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  
  gpio.Mode = GPIO_MODE_OUTPUT_PP;
  gpio.Pin = GPIO_PIN_5 | GPIO_PIN_13;
  gpio.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &gpio);
  
  gpio.Pin = GPIO_PIN_6;
  HAL_GPIO_Init(GPIOE, &gpio);
}

void test_init(void)
{
  test_led_init();
  SegDisplay_Init();
  
  test_cgis[0].pcCGIName = "/devctrl";
  test_cgis[0].pfnCGIHandler = test_cgis_handler;
  test_cgis[1].pcCGIName = "/devctrl.ssi";
  test_cgis[1].pfnCGIHandler = test_cgis_handler;
  test_cgis[2].pcCGIName = "/devctrl.html";
  test_cgis[2].pfnCGIHandler = test_cgis_handler;
  http_set_cgi_handlers(test_cgis, LWIP_ARRAYSIZE(test_cgis));
  http_set_ssi_handler(test_ssi_handler, NULL, 0);
}

程序运行结果:
访问网址:http://stm32f103ze/devctrl?led1=toggle&led2=toggle&led3=toggle&num=-13.9
可以看到数码管显示了-13.9这个数字。每访问一次网页,三个LED灯都会切换一次状态。
还可以在网页中通过表单控件动态改变URL参数的值,表单上也会显示当前LED和数码管的状态。

使用新式CGI功能

下一篇:lwip-2.1.3自带的httpd网页服务器使用教程(四)POST类型表单的解析和文件上传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/759436.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV的HSV颜色空间在无人车中颜色识别的应用

RGB属于三基色空间&#xff0c;是大家最为熟悉的&#xff0c;看到的任何一种颜色都可以由三基色进行混合而成。然而一般对颜色空间的图像进行有效处理都是在HSV空间进行的&#xff0c;HSV(色调Hue,饱和度Saturation,亮度Value)是根据颜色的直观特性创建的一种颜色空间, 也称六角…

如何撤销git上一次的commit(或已push)

如何撤销git上一次的commit&#xff08;或已push&#xff09; 当多人开发时&#xff0c;我们本地commit后&#xff0c;刚要push&#xff0c;发现忘记pull最新代码&#xff0c;此时会有冲突push失败&#xff0c; 我们想要撤销最近的一次commit 我们先简单介绍一下git git有三大…

GreenPlum数据库日常维护

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

使用 YOLOv8 和 Streamlit 构建实时对象检测和跟踪应用程序:第3部分:添加跟踪算法

介绍 对象跟踪是随着时间的推移识别一系列帧中的特定对象或多个对象的过程。它涉及定位对象在每个帧中的位置并跟踪其跨帧的移动。对象跟踪在各个领域都有广泛的应用,包括监控、机器人、自动驾驶、运动分析等。 跟踪算法使用各种技术(例如颜色直方图、运动分析、深度学习等)…

【多线程】(二)线程安全问题与线程同步

文章目录 一、多线程带来的风险1.1 观察线程不安全1.2 线程安全概念1.3 线程不安全的原因1.4 线程安全的解决方法 二、synchronized关键字2.1 synchronized 的特性2.2 synchronized 使用示例2.3 Java 标准库中的线程安全类 三、volatile关键字3.1 保证内存可见性3.2 禁止指令重…

Java反射的应用:动态代理

代理设计模式的原理 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。 对于静态代理&#xff0c;特征是代理类和目标对象的类都是在编译期间确定下来&#xff0c;不利于程…

基于FPGA的按键消抖

文章目录 基于FPGA的按键消抖一、按键消抖原理二、按键消抖代码三、仿真代码编写四&#xff1a;总结 基于FPGA的按键消抖 一、按键消抖原理 按键抖动&#xff1a;按键抖动通常的按键所用开关为机械弹性开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性…

怎么使用Netty解码自定义通信协议

网络协议的基本要素 一个完备的网络协议需要具备哪些基本要素 魔数&#xff1a;魔数是通信双方协商的一个暗号&#xff0c;通常采用固定的几个字节表示。魔数的作用是防止任何人随便向服务器的端口上发送数据。协议版本号&#xff1a;随着业务需求的变化&#xff0c;协议可能…

SAP顾问生涯闲记:在SAP工作是什么体验

又有一段时间没更新自己的公众号了&#xff0c;为什么突然决定新开一篇SAP顾问生涯闲记系列的文章呢&#xff0c;是因为最近很荣幸地当选了SAP雇主品牌推广大使&#xff0c;作为SAP官方的推广大使在收获这份荣誉的同时&#xff0c;也承担了一些工作以及责任。 集结完毕︱SAP雇…

Flask_实现token鉴权

目录 1、安装依赖 2、实现代码 3、测试 源码等资料获取方法 1、安装依赖 pip install flask pip install pycryptodome 2、实现代码 import random import string import time import base64from functools import wrapsfrom flask import Flask, jsonify, session, req…

苍穹外卖day02——员工管理功能代码开发+分类管理代码导入

目录 新增员工——需求分析与设计 产品原型 接口设计: 数据库设计: 新增员工——代码开发 在Controller层中 在Service层中 在Mapper层中 功能测试 接口文档测试: 前后端联调测试: 新增员工——代码完善 ​编辑 第一个问题 第二个问题 员工分页查询 需求分析与设计 …

PostgreSQL考试难不难 ?

当涉及到PostgreSQL考试的详细难度&#xff0c;以下是一些可能涉及的主题和考点&#xff0c;这些主题在不同的考试中可能有所不同&#xff1a; 1.数据库基础知识&#xff1a;数据库的基本概念、关系型数据库模型、表、字段、主键、外键等。 2.SQL语言&#xff1a;对SQL语言的掌…

数据集——个人收集标注与使用过的数据集

前言 这是一个我个人在工作和学习中使用过以数据集的一部分&#xff0c;有语义分割&#xff0c;目标识别&#xff0c;人像抠图等几个大类&#xff0c;这只是我用过数据集中的一部分&#xff0c;这些数据集有小一部分是来源自网络&#xff0c;很大一部分都是我自己收集。 一、…

【动手学深度学习】--05.权重衰退

文章目录 权重衰退1.原理1.1使用均方范数作为硬性限制1.2使用均方范数作为柔性限制1.3对最优解的影响1.4参数更新法则 2.从零开始实现权重衰退2.1初始化模型参数2.2定义L2范数惩罚2.3训练2.4忽略正则化直接训练2.5使用权重衰退 3.简洁实现 权重衰退 学习视频&#xff1a;权重衰…

在网格化数据集上轻松执行 2D 高通、低通、带通或带阻滤波器研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud设置白名单

目录 前提条件 操作步骤 下一步 在 Zilliz Cloud 中,白名单是针对项目的安全设置,适用于项目下的所有集群。设置白名单后,仅白名单中的 IP 地址可以访问您项目下的所有集群。白名单能够有效降低受到恶意攻击的风险 本教程将介绍如何设置白名单。 前提条件 确保满足以…

EasyX测试布局代码

#include <iostream> #include <algorithm> #include <graphics.h> // 引用图形库头文件 #include <conio.h> #include <unordered_map> #include <Windows.h> #include "layout/LayoutSystem.h"#define DEFAULT_PANELS_LAYOUT…

谈二级索引

前提&#xff1a; 在数据库中&#xff0c;1、索引分为聚簇索引和非聚簇索引两类。2、所有索引的数据结构都是树&#xff0c;查找树上的节点数据时通过用二分法来锁定数据范围&#xff0c;指定数据排序的规则&#xff0c;比如&#xff1a;有小到大&#xff0c;对比之后最终确定…

Sequencer使用心得

在关卡序列中设置了触发蓝图的关键帧&#xff0c;为什么播放的时候没有触发蓝图事件呢&#xff1f; 在关卡序列中触发蓝图&#xff0c;一般是将蓝图添加到轨道中&#xff0c;设置触发器&#xff0c;在对应的关键帧中&#xff0c;绑定蓝图事件。 一般的话&#xff0c;点击播…