笔记

要写板子的下位机固件程序了,片上用到了http服务器。
第一个子任务就是先将出厂生产的功能搞了,这样需要的外部文件就都能通过片上http服务器传到下位机本地存储中了。

最终的素材都是前端同事提供的。想将带纯html上传文件功能的html做成数组,用来响应http请求。
这样出厂生产的时候有用。格式化存储这些动作命令的发出,上传固件更新包,上传web同事的更新包都用的到。丑一点不怕,只是出厂生产和升级用。

纯html好处是,可以单独运行,不用先将js拷贝进存储。只通过这个代码中的纯html数组开个头,等正式运行时,就可以用专业web同事做的漂亮网页。

试验

纯html网页

纯html上传文件,好像只能用form表单提交。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>upload file to http server inside</title>    
</head>
<body>
	<form method="POST" enctype="multipart/form-data" action="file_upload.cgi">
	  file_to_save_to: <input type="text" name="file_to_save_to"><br/>
	  file_to_upload: <input type="file" name="file_to_upload"><br/>
	  <input type="submit" value="upload"><br/>
	</form>
</body>
</html>

很短的一段html, 用工具转成C数组也不大。

html ios 上传文件 纯html上传文件_前端

本地测试用的http服务器

http服务监听IP在js中写死的,假设本机IP为 192.168.1.23
http服务监听端口也是在js中写死的, 假设端口为8080

现在本地测试,先用nodejs代码做一段可以get 提供html + post存文件的功能,命名为 local_http_server.js。
等正式用时,http服务器是MCU片上实现的。

console.log("C:\\Program Files\\nodejs node.exe server.js");

var http = require("http"),
	url  = require("url"),
	path = require("path"),
	fs   = require("fs");
	
http.createServer(function (request, response) {
	var postData = "";
	var file_name = url.parse(request.url).pathname;
	request.setEncoding('utf-8');
	if (file_name==""||file_name=="/") {
		file_name="/index.htm";
	}
	var pathname=__dirname+file_name;
	if(request.method == "GET" || request.method == "get")
	{
		fs.exists(pathname,function(exists){
			if(exists){
				switch(path.extname(pathname)){
					case ".htm":
						response.writeHead(200, {"Content-Type": "text/html"});
						break;			
					case ".html":
						response.writeHead(200, {"Content-Type": "text/html"});
						break;					
					case ".TXT":
						response.writeHead(200, {"Content-Type": "application/json","Pragma": "no-cache","Cache-Control": "no-cache, no-store, max-age=0","Expires":"1L"});
						break;							
					case ".js":
						response.writeHead(200, {"Content-Type": "text/javascript","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;
					case ".css":
						response.writeHead(200, {"Content-Type": "text/css","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;
					case ".gif":
						response.writeHead(200, {"Content-Type": "image/gif","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;
					case ".jpg":
						response.writeHead(200, {"Content-Type": "image/jpeg","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;
					case ".png":
						res.writeHead(200, {"Content-Type": "image/png","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;
					case ".mp3":
						response.writeHead(200, {"Content-Type": "audio/mpeg","Content-Length":40124,"Content-Range":"bytes 0-40123/40124","Cache-control": "max-age=315360000000","Expires":"Thu, 15 Apr 2100 20:00:00 GMT"});
						break;						
					default:
						response.writeHead(200, {"Content-Type": "application/octet-stream"});
				}
				fs.readFile(pathname,function (err,data){
					response.end(data);
				});
			} 
			else {
				response.writeHead(404, {"Content-Type": "text/html"});
				response.end("<h1>404 Not Found</h1>");
			}
		});	
	}
	else{
		// 数据块接收中
		request.addListener("data", function (postDataChunk) {
			postData += postDataChunk;
		});	
		// 数据接收完毕,执行回调函数
		request.addListener("end", function () {
			fs.writeFile(pathname, postData, function(err){
				if(err){
					console.log("writeFile fail");
					response.writeHead(200, {"Content-Type": "text/html"});
					response.end("POST fail!");						
				}else{
					response.writeHead(200, {"Content-Type": "text/html"});
					response.end("POST Successfully!");							
				}	
			});
		});		
	}
}).listen(8080, "192.168.1.23");

console.log("Server running...");

本地测试过程

我计算机上做其他试验时,已经装了nodejs, 版本是node10.16.3

node -v
v10.16.3

新版node和老版node写法基本一样。

启动nodejs实现的http服务器

写个bat来弄

@echo off
rem use nodjs load .js
cls
node local_http_server.js

启动后,用netstat看看http监听端口启动没有?

netstat -an | grep 8080

为了防止跨域问题,要实现上传的html(case_file_upload.html)要和local_http_server.js放在一起。
然后在浏览器中输入 http://192.168.1.23:8080/case_file_upload.html
上传文件后,在服务器目录(.js同级目录)中保存为file_upload.cgi

上传后保存的文件

file_upload.cgi

------WebKitFormBoundaryh0IpywtmAbOlOn0z
Content-Disposition: form-data; name="file_to_save_to"

web/update
------WebKitFormBoundaryh0IpywtmAbOlOn0z
Content-Disposition: form-data; name="file_to_upload"; filename="test1.log"
Content-Type: application/octet-stream

[>>
  test1.cpp
  test1.vcxproj -> d:\tmp\test1\test1\Debug\test1.exe
<<]
------WebKitFormBoundaryh0IpywtmAbOlOn0z--

保存后的文件,连http报文的中间字符和http与上传文件之间边界都保存了。
------WebKitFormBoundary这行就是每个上传数据段的part开始标记。
这样就可以将form表单提交的多个part分开。然后将不关心的内容剔除掉,就是form表单提交的文本信息和文件内容。

搞下位机的同学可能html和js都不熟,可以用这种form表单提交的方法先搞一下。
通过分析保存后的file_upload.cgi中的特定测试用文本信息,来干不同的活。

等正式用的时候,就是前端同学来实现,响应他们的post请求来干活。