物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。
硬件环境:飞腾派开发板(国产E2000处理器)
软件环境:飞腾派OS(Phytium Pi OS)
硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板硬件与系统
lighttpd服务器部署参考另一篇博客:物联网网关Web服务器--lighttpd服务器部署与应用测试
1、部署与运行效果
//启动服务器
user@phytiumpi:/var/www$ sudo service lighttpd start//服务器根目录/var/www部署如下目录与文件
user@phytiumpi:/var/www$ tree
.
`-- html|-- bmi.png|-- bmi_index.png|-- cgi-bin| `-- bmi.cgi`-- index.html2 directories, 4 files//文件权限如下
user@phytiumpi:/var/www$ ls -lh html/*
-rw-r--r-- 1 root root 36K Jan 16 11:07 html/bmi.png
-rw-r--r-- 1 root root 13K Jan 16 14:08 html/bmi_index.png
-rw-r--r-- 1 root root 688 Jan 16 11:07 html/index.htmlhtml/cgi-bin:
total 16K
-rwxr-xr-x 1 root root 15K Jan 16 13:51 bmi.cgi//bmi.cgi文件类型
user@phytiumpi:/var/www$ file html/cgi-bin/bmi.cgi
html/cgi-bin/bmi.cgi: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=f39d7a4a7551ef3e3b4eba59a12959d4bc636032, for GNU/Linux 3.7.0, not stripped
-
浏览器运行
输入身高与体重信息,点击“计算”按钮,会提交当前网页中的表单数据到Web服务器并返回计算后的BMI数据。
2、Index网页文件说明
index.html是web服务器默认的页面文件,主要作用就是显示一个静态页面,提交当前页面后指定的cgi程序执行处理。
//action 指定了cgi-bin\bmi.cgi为提交后执行的程序文件
<form action="cgi-bin\bmi.cgi" method="get">
index.html源码:
<html>
<body>
<div align="center">
<form action="cgi-bin\bmi.cgi" method="get"> <table> <tr><td rowspan="3"><img src="bmi.png" hight="60" width="120"></td><td align="center" colspan="3"><h2>体重指数(BMI)计算器</h2></td></tr><tr><td >身高 : <input type="number" name="cm" min="1" max="300" size="3"> cm </td><td >体重 : <input type="number" name="kg" min="1" max="500" size="3"> kg </td><td align="center" ><input type=submit value=" 计 算 " size="16"> </td></tr><tr><td align="center" colspan="3">BMI = <input type="text" name="ret" value="" size="3" readonly></tr> </table>
</form>
</br><img src=bmi_index.png >
</div>
</body>
</html>
3、HTTP 请求处理功能说明
通过getvalue.h头文件实现。
宏定义和全局变量
#define FIELD_LEN 60
#define NV_PAIRS 15 typedef struct name_value_st{char name[FIELD_LEN + 1];char value[FIELD_LEN + 1];
} name_value;name_value name_val_pairs[NV_PAIRS];
int num_pairs = 0;/*pairs number*/
const char *M = NULL;
const char *L = NULL;
const char *S = NULL;
static int iread = 0;
-
FIELD_LEN
宏定义了每个名称或值的最大长度为 60。 -
NV_PAIRS
宏定义了可以处理的名称 - 值对的最大数量为 15。 -
name_value
结构体包含两个字符数组name
和value
,分别用于存储名称和值,长度为FIELD_LEN + 1
。 -
name_val_pairs
是name_value
结构体的数组,用于存储多个名称 - 值对。 -
num_pairs
用于记录实际存储的名称 - 值对的数量。 -
M
、L
、S
是指向常量字符的指针,初始化为NULL
,可能用于存储请求方法、内容长度和查询字符串。 -
iread
是静态整型变量,可能用于记录读取值的次数。
函数声明
void unescape_url(char *url);
void set_env(const char *r_mth, const char *c_len,const char *q_str);
char* get_value(const char *name);
int get_input(void);
void send_error(char *error_test);
char x2c(char *what);
void load_nv_pair(char *tmp_buffer, int nv_entry_number_to_load);
-
unescape_url(char *url)
:对 URL 进行转义处理。 -
set_env(const char *r_mth, const char *c_len,const char *q_str)
:设置环境变量,将传入的三个参数存储到全局指针M
、L
和S
中。 -
get_value(const char *name)
:根据传入的名称查找并返回对应的value
。 -
get_input(void)
:获取输入数据,根据请求方法(POST 或 GET)将数据存储在ip_data
中,并将数据解析为名称 - 值对存储在name_val_pairs
中。 -
send_error(char *error_text)
:输出错误信息,以 HTML 格式输出错误信息。 -
x2c(char *what)
:将十六进制表示的字符转换为对应的 ASCII 字符。 -
load_nv_pair(char *tmp_buffer, int nv_entry_number_to_load)
:将tmp_buffer
中的名称 - 值对加载到name_val_pairs
数组的指定条目中。
set_env(const char *r_mth, const char *c_len,const char *q_str)
void set_env(const char *r_mth, const char *c_len,const char *q_str)
{M = r_mth;L = c_len;S = q_str;
}
-
功能:将传入的三个参数
r_mth
、c_len
和q_str
分别赋值给全局指针M
、L
和S
,用于存储环境信息。
get_value(const char *name)
char* get_value(const char *name)
{int nv_entry_number = 0;int i = 0;char* val = NULL;char *tname = NULL;if(iread == 0){ if (!get_input()){return "error";exit(EXIT_FAILURE);}}for(i = 0; i < num_pairs; i++ ){ val = name_val_pairs[nv_entry_number].value;tname = name_val_pairs[nv_entry_number].name;nv_entry_number++;if( strcmp(tname,name) == 0 ){ break;}else{ val = NULL; tname = NULL;}}iread++;//read value timesreturn val; exit(EXIT_SUCCESS);
}
-
功能:
-
首先,如果
iread
为 0,则调用get_input()
函数获取输入数据。如果get_input()
失败,返回"error"
并终止程序。 -
然后遍历
name_val_pairs
数组,比较每个名称 - 值对的名称部分和传入的name
,如果匹配,将对应的value
存储在val
中。 -
增加
iread
的值,表示读取值的次数。 -
最后返回找到的
value
,如果未找到,返回NULL
。
-
get_input(void)
int get_input(void)
{int nv_entry_number = 0;int got_data = 0;char *ip_data = NULL;int ip_length = 0;char tmp_buffer[(FIELD_LEN * 2) + 2];int tmp_offset = 0;char *tmp_char_ptr = NULL;int chars_processed = 0;tmp_char_ptr = (char*)M;if ( tmp_char_ptr){if(strcmp(tmp_char_ptr, "POST") == 0){tmp_char_ptr = (char*)L;if (tmp_char_ptr){ip_length = atoi(tmp_char_ptr);ip_data = malloc(ip_length + 1);if (fread(ip_data, 1, ip_length, stdin)!= ip_length){send_error("Bad read from stdin");return(0);}ip_data[ip_length] = '\0';got_data = 1;}}}tmp_char_ptr = (char*)M;if ( tmp_char_ptr){if(strcmp(tmp_char_ptr, "GET") == 0){tmp_char_ptr = (char*)S;if (tmp_char_ptr){ip_length = strlen(tmp_char_ptr);ip_data = malloc(ip_length + 1);strcpy(ip_data, (char*)S);ip_data[ip_length] = '\0';got_data = 1;}}}if (!got_data){send_error("No data received");}if (ip_length <= 0){send_error("Input length <= 0");return(0);}memset(name_val_pairs, '\0', sizeof(name_val_pairs));tmp_char_ptr = ip_data;while (chars_processed <= ip_length && nv_entry_number < NV_PAIRS){tmp_offset = 0;while (*tmp_char_ptr && *tmp_char_ptr!= '&' && tmp_offset < FIELD_LEN){tmp_buffer[tmp_offset] = *tmp_char_ptr;tmp_offset++;tmp_char_ptr++;chars_processed++;}tmp_buffer[tmp_offset] = '\0';load_nv_pair(tmp_buffer, nv_entry_number);tmp_char_ptr++;nv_entry_number++;}free(ip_data);ip_data = NULL;return(1);
}
-
功能:
-
首先,通过
M
检查请求方法。 -
如果是
POST
方法,通过L
获取内容长度,分配足够的内存给ip_data
,使用fread
从标准输入读取数据,处理读取错误。 -
如果是
GET
方法,通过S
获取查询字符串,分配内存给ip_data
,复制查询字符串,添加字符串结束符。 -
检查是否有数据,如果没有数据,调用
send_error
函数报错。 -
检查输入长度是否小于等于 0,若是则报错。
-
清空
name_val_pairs
数组。 -
遍历
ip_data
,将数据存储在tmp_buffer
中,遇到&
符号或达到FIELD_LEN
长度时,调用load_nv_pair
函数将数据存储到name_val_pairs
数组中。 -
释放
ip_data
的内存。
-
send_error(char *error_text)
void send_error(char *error_text)
{printf("Content-Type: text/html\r\n");printf("\r\n");printf("Woops:- %s\r\n",error_text);
}
-
功能:输出 HTML 头信息和错误信息,用于向用户反馈错误信息。
load_nv_pair(char *tmp_buffer, int nv_entry)
void load_nv_pair(char *tmp_buffer, int nv_entry)
{int chars_processed = 0;char *src_char_ptr = NULL;char *dest_char_ptr = NULL;src_char_ptr = tmp_buffer;dest_char_ptr = name_val_pairs[nv_entry].name;while (*src_char_ptr && *src_char_ptr!= '=' && chars_processed < FIELD_LEN){if (*src_char_ptr == '+'){*dest_char_ptr = ' ';}else{*dest_char_ptr = *src_char_ptr;}dest_char_ptr++;src_char_ptr++;chars_processed++;}if (*src_char_ptr == '='){num_pairs++;src_char_ptr++;dest_char_ptr = name_val_pairs[nv_entry].value;chars_processed = 0;while (*src_char_ptr && *src_char_ptr!= '=' && chars_processed < FIELD_LEN){if (*src_char_ptr == '+'){*dest_char_ptr = ' ';}else{*dest_char_ptr = *src_char_ptr;}dest_char_ptr++;src_char_ptr++;chars_processed++;}}unescape_url(name_val_pairs[nv_entry].name);unescape_url(name_val_pairs[nv_entry].value);
}
-
功能:
-
将
tmp_buffer
中的数据解析为名称 - 值对,将名称存储在name_val_pairs[nv_entry].name
中,将值存储在name_val_pairs[nv_entry].value
中。 -
将
+
替换为空格。 -
调用
unescape_url
函数对名称和值进行 URL 转义处理。
-
unescape_url(char *url)
void unescape_url(char *url)
{int x,y;for (x=0,y=0; url[y]; ++x,++y ){if ( (url[x] = url[y]) == '%'){url[x] = x2c(&url[y+1]);y += 2;}}url[x] = '\0';
}
-
功能:
-
遍历
url
字符串。 -
当遇到
%
时,调用x2c
函数将后面的两个字符转换为对应的 ASCII 字符。
-
x2c(char *what)
char x2c(char *what)
{register char digit;digit = (what[0] >= 'A'? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));digit *= 16;digit += (what[1] >= 'A'? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));return(digit);
}
-
功能:将十六进制表示的字符(如
%xx
)转换为对应的 ASCII 字符。
4、应用功能主程序说明
通过bmi.c程序实现。关键代码分析说明如下:
set_env(getenv("REQUEST_METHOD"),getenv("CONTENT_LENGTH"),getenv("QUERY_STRING"));
-
getenv("REQUEST_METHOD")
:该函数用于获取名为REQUEST_METHOD
的环境变量的值。在 HTTP 服务器环境中,REQUEST_METHOD
通常包含请求的方法,例如GET
、POST
、PUT
等。 -
getenv("CONTENT_LENGTH")
:该函数用于获取名为CONTENT_LENGTH
的环境变量的值。在 HTTP 请求中,如果是POST
方法,CONTENT_LENGTH
表示请求体的长度。 -
getenv("QUERY_STRING")
:该函数用于获取名为QUERY_STRING
的环境变量的值。在 HTTP 的GET
请求中,QUERY_STRING
包含了 URL 中的查询部分(即?
后面的部分)。
val_cm = get_value("cm"); val_kg = get_value("kg");
-
通过getvalue.h文件中的自定义函数get_value,可根据传入的名称查找并返回对应的字符串值。
bmi.c文件源码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include "getvalue.h"int main(int argc, char *argv[])
{char *val_cm = NULL;char *val_kg = NULL;int cm,kg,len;float cm_f=0.0,kg_f=0.0,bmi=0.0;set_env(getenv("REQUEST_METHOD"),getenv("CONTENT_LENGTH"),getenv("QUERY_STRING")); val_cm = get_value("cm"); val_kg = get_value("kg"); cm = atoi(val_cm);kg = atoi(val_kg);cm_f = (cm + 0.0) / 100;kg_f = kg + 0.0;bmi = kg_f/(cm_f*cm_f);//计算bmi数值//下面输出信息都是HTML文件输出printf( "Content-type:text/html\n\n" ); printf("<html><body><div align=\"center\">\n");//输出调试信息printf("Debug INFO:CM=%f,KG=%f,BMI=%f \n",cm_f,kg_f,bmi);printf("<form action=\"bmi.cgi\" method=\"get\"><table> \n");printf("<tr><td rowspan=\"3\"><img src=\"../bmi.png\" hight=\"60\" width=\"120\"></td> \n");printf("<td align=\"center\" colspan=\"3\"><h2>体重指数(BMI)计算器</h2></td></tr> \n");printf("<tr><td >身高 : <input type=\"number\" name=\"cm\" min=\"1\" max=\"300\" size=\"3\"> cm </td> \n");printf("<td >体重 : <input type=\"number\" name=\"kg\" min=\"1\" max=\"500\" size=\"3\"> kg </td> \n");printf("<td align=\"center\" ><input type=submit value=\" 计 算 \" size=\"16\"> </td></tr> \n");printf("<tr><td align=\"center\" colspan=\"3\">BMI = \n");if(bmi == 0.0)printf("<input type=\"text\" name=\"ret\" value=\" \" size=\"3\" readonly></tr> \n");elseprintf("<input type=\"text\" name=\"ret\" value=\" %.1f \" size=\"3\" readonly></tr> \n",bmi); printf("</table></form></br><img src=\"../bmi_index.png\" > \n");printf("</div></body> </html> \n");return 0;
}
相关文章:

物联网网关Web服务器--CGI开发实例BMI计算
本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境:飞腾派开发板(国产E2000处理器) 软件环境:飞腾派OS(Phytium Pi OS) 硬件平台参考另一篇博客:国产化ARM平台-飞腾派开发板…...

计算机网络 (51)鉴别
前言 计算机网络鉴别是信息安全领域中的一项关键技术,主要用于验证用户或信息的真实性,以及确保信息的完整性和来源的可靠性。 一、目的与重要性 鉴别的目的是验明用户或信息的正身,对实体声称的身份进行唯一识别,以便验证其访问请…...

【Docker】搭建一个功能强大的自托管虚拟浏览器 - n.eko
前言 本教程基于群晖的NAS设备DS423的docker功能进行搭建,DSM版本为 DSM 7.2.2-72806 Update 2。 n.eko 支持多种类型浏览器在其虚拟环境中运行,本次教程使用 Chromium 浏览器镜像进行演示,支持访问内网设备和公网地址。 简介 n.eko 是…...

论文笔记(六十二)Diffusion Reward Learning Rewards via Conditional Video Diffusion
Diffusion Reward Learning Rewards via Conditional Video Diffusion 文章概括摘要1 引言2 相关工作3 前言4 方法4.1 基于扩散模型的专家视频建模4.2 条件熵作为奖励4.3 训练细节 5 实验5.1 实验设置5.2 主要结果5.3 零样本奖励泛化5.4 真实机器人评估5.5 消融研究 6 结论 文章…...

探索 Stable-Diffusion-Webui-Forge:更快的AI图像生成体验
目录 简介🌟 主要特点📥 安装步骤1. 下载2. 配置环境和安装依赖3. 模型目录说明 🚀 运行 Stable-Diffusion-Webui-Forge1. 进入项目目录2. 运行项目3. 打开页面 🎨 使用体验常见问题📝 小结 简介 Stable-Diffusion-We…...

Redis使用基础
1 redis介绍 Redis(Remote Dictionary Server ),即远程字典服务 ! 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库。 使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并…...

PyCharm+RobotFramework框架实现UDS自动化测试- (四)项目实战0x10
1.环境搭建 硬件环境:CANoe、待测设备(包含UDS诊断模块) 2.pythonPyCharm环境 pip install robotframework pip install robotframework-ride pip install openpyxl pip install udsoncan pip install python-can pip install can-isotp3…...

【TCP】rfc文档
tcp协议相关rfc有哪些 TCP(传输控制协议)是一个复杂的协议,其设计和实现涉及多个RFC文档。以下是一些与TCP协议密切相关的RFC文档列表,按照时间顺序排列,涵盖了从基础定义到高级特性和优化的各个方面: 基…...

【SpringCloud】黑马微服务学习笔记
目录 1. 关于微服务 ?1.1 微服务与单体架构的区别 ?1.2 SpringCloud 技术 2. 学习前准备 ?2.1 环境搭建 ?2.2 熟悉项目 3. 正式拆分 ?3.1 拆分商品功能模块 ?3.2 拆分购物车功能模块 4. 服务调用 ?4.1 介绍 ?4.2 RustTemplate?的使用 4.3 服务治理-注册中…...
梯度提升决策树树(GBDT)公式推导
### 逻辑回归的损失函数 逻辑回归模型用于分类问题,其输出是一个概率值。对于二分类问题,逻辑回归模型的输出可以表示为: \[ P(y 1 | x) \frac{1}{1 e^{-F(x)}} \] 其中 \( F(x) \) 是一个线性组合函数,通常表示为ÿ…...

【MySQL】表的基本操作
??表的基本操作 文章目录: 表的基本操作 创建查看表 创建表 查看表结构 表的修改 表的重命名 表的添加与修改 删除表结构 总结 前言: 在数据库中,数据表是存储和组织数据的基本单位,对于数据表的操作是每个程序员需要烂熟…...

项目中使用的是 FastJSON(com.alibaba:fastjson)JSON库
从你的 pom.xml 文件中可以看到,项目明确依赖了以下 JSON 库: FastJSON: <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version> </depende…...
Flutter中PlatformView在鸿蒙中的使用
Flutter中PlatformView在鸿蒙中的使用 概述在Flutter中的处理鸿蒙端创建内嵌的鸿蒙视图创建PlatformView创建PlatformViewFactory创建plugin,注册platformview注册插件 概述 集成平台视图(后称为平台视图)允许将原生视图嵌入到 Flutter 应用…...

音频入门(一):音频基础知识与分类的基本流程
音频信号和图像信号在做分类时的基本流程类似,区别就在于预处理部分存在不同;本文简单介绍了下音频处理的方法,以及利用深度学习模型分类的基本流程。 目录 一、音频信号简介 1. 什么是音频信号 2. 音频信号长什么样 二、音频的深度学习分…...
规避路由冲突
路由冲突是指在网络中存在两个或多个路由器在进行路由选择时出现矛盾,导致网络数据包无法正确传输,影响网络的正常运行。为了规避路由冲突,可以采取以下措施: 一、合理规划IP地址 分配唯一IP:确保每个设备在网络中都有…...

SQLmap 自动注入 -02
1: 如果想获得SQL 数据库的信息,可以加入参数: -dbs sqlmap -u "http://192.168.56.133/mutillidae/index.php?pageuser-info.php&usernamexiaosheng&passwordabc&user-info-php-submit-buttonViewAccountDetails" --batch -p username -dbs…...

4.JoranConfigurator解析logbak.xml
文章目录 一、前言二、源码解析GenericXMLConfiguratorlogback.xml解析通过SaxEvent构建节点model解析model节点DefaultProcessor解析model 三、总结 一、前言 上一篇介绍了logback模块解析logback.mxl文件的入口, 我们可以手动指定logback.xml文件的位置, 也可以使用其它的名…...
React 19 新特性总结
具体详见官网: 中文:React 19 新特性 英文:React 19 新特性 核心新特性 1. Actions 解决问题:简化数据变更和状态更新流程 以前需要手动处理待定状态、错误、乐观更新和顺序请求需要维护多个状态变量(isPending, error 等) 新…...

kafka学习笔记6 ACL权限 —— 筑梦之路
在Kafka中,ACL(Access Control List)是用来控制谁可以访问Kafka资源(如主题、消费者组等)的权限机制。ACL配置基于Kafka的kafka-acls.sh工具,能够管理对资源的读取、写入等操作权限。 ACL介绍 Kafka的ACL是…...
【Java】Java抛异常到用户界面公共封装
前言 在Java中处理代码运行异常是常见的技术点之一,我们大部分会使用封装的技巧将异常进行格式化输出,方便反馈给用户界面,也是为了代码复用 看看这行代码是怎么处理异常的 CommonExceptionType.SimpleException.throwEx("用户信息不…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

Linux入门课的思维导图
耗时两周,终于把慕课网上的Linux的基础入门课实操、总结完了! 第一次以Blog的形式做学习记录,过程很有意思,但也很耗时。 课程时长5h,涉及到很多专有名词,要去逐个查找,以前接触过的概念因为时…...
【大厂机试题解法笔记】矩阵匹配
题目 从一个 N * M(N ≤ M)的矩阵中选出 N 个数,任意两个数字不能在同一行或同一列,求选出来的 N 个数中第 K 大的数字的最小值是多少。 输入描述 输入矩阵要求:1 ≤ K ≤ N ≤ M ≤ 150 输入格式 N M K N*M矩阵 输…...

NineData数据库DevOps功能全面支持百度智能云向量数据库 VectorDB,助力企业 AI 应用高效落地
NineData 的数据库 DevOps 解决方案已完成对百度智能云向量数据库 VectorDB 的全链路适配,成为国内首批提供 VectorDB 原生操作能力的服务商。此次合作聚焦 AI 开发核心场景,通过标准化 SQL 工作台与细粒度权限管控两大能力,助力企业安全高效…...
GitHub 常见高频问题与解决方案(实用手册)
1.Push 提示权限错误(Permission denied) 问题: Bash Permission denied (publickey) fatal: Could not read from remote repository. 原因: 没有配置 SSH key 或使用了 HTTPS 而没有权限…...

【Axure高保真原型】图片列表添加和删除图片
今天和大家分享图片列表添加和删除图片的原型模板,效果包括: 点击图片列表的加号可以显示图片选择器,选择里面的图片; 选择图片后点击添加按钮,可以将该图片添加到图片列表; 鼠标移入图片列表的图片&…...

[electron]预脚本不显示内联script
script-src self 是 Content Security Policy (CSP) 中的一个指令,它的作用是限制加载和执行 JavaScript 脚本的来源。 具体来说: self 表示 当前源。也就是说,只有来自当前网站或者当前页面所在域名的 JavaScript 脚本才被允许执行。"…...