估计也会有像我这样直接调用示例程序来跑,发现无法访问的人应该还会有,官方示例给的有点太随意,有些注释让人困惑。
SDWebServer例程修改使用记录(ESP32)文件服务器
/*
SDWebServer - Example WebServer with SD Card backend for esp8266
访问方式说明:
查阅SD根目录文件信息: 直接使用浏览器访问SD卡根目录方式:http://esp32sd.local/list?dir=/
删除SD卡目录下的一个文件:需要借助Restclient工具,并设置访问方式为DELETE方式,访问格式:http://esp32sd.local/edit?=//foo.txt
Have a FAT Formatted SD Card connected to the SPI port of the ESP8266
The web root is the SD Card root folder
File extensions with more than 3 charecters are not supported by the SD Library
File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter
index.htm is the default index (works on subfolders as well)
upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
*/
#include
#include
#include
#include
#include
#include
#include "FS.h"
#define Serial Serial
const char* ssid = "MERCURY_D268G";
const char* password = "pba5ayzk";
const char* host = "esp32sd";
WebServer server(80);
static bool hasSD = false;
File uploadFile;
void returnOK() {
server.send(200, "text/plain", "");
}
void returnFail(String msg) {
server.send(500, "text/plain", msg + "\r\n");
}
bool loadFromSdCard(String path) {
String dataType = "text/plain";
if (path.endsWith("/")) {
path += "index.htm";
}
if (path.endsWith(".src")) {
path = path.substring(0, path.lastIndexOf("."));
} else if (path.endsWith(".htm")) {
dataType = "text/html";
} else if (path.endsWith(".css")) {
dataType = "text/css";
} else if (path.endsWith(".js")) {
dataType = "application/javascript";
} else if (path.endsWith(".png")) {
dataType = "image/png";
} else if (path.endsWith(".gif")) {
dataType = "image/gif";
} else if (path.endsWith(".jpg")) {
dataType = "image/jpeg";
} else if (path.endsWith(".ico")) {
dataType = "image/x-icon";
} else if (path.endsWith(".xml")) {
dataType = "text/xml";
} else if (path.endsWith(".pdf")) {
dataType = "application/pdf";
} else if (path.endsWith(".zip")) {
dataType = "application/zip";
}
File dataFile = SD.open(path.c_str());
if (dataFile.isDirectory()) {
path += "/index.htm";
dataType = "text/html";
dataFile = SD.open(path.c_str());
}
if (!dataFile) {
return false;
}
if (server.hasArg("download")) {
dataType = "application/octet-stream";
}
if (server.streamFile(dataFile, dataType) != dataFile.size()) {
Serial.println("Sent less data than expected!");
}
dataFile.close();
return true;
}
void handleFileUpload() {
if (server.uri() != "/edit") {
return;
}
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
if (SD.exists((char *)upload.filename.c_str())) {
SD.remove((char *)upload.filename.c_str());
}
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
Serial.print("Upload: START, filename: "); Serial.println(upload.filename);
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (uploadFile) {
uploadFile.write(upload.buf, upload.currentSize);
}
Serial.print("Upload: WRITE, Bytes: "); Serial.println(upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) {
if (uploadFile) {
uploadFile.close();
}
Serial.print("Upload: END, Size: "); Serial.println(upload.totalSize);
}
}
void deleteRecursive(String path) {
File file = SD.open((char *)path.c_str());
if (!file.isDirectory()) {
file.close();
SD.remove((char *)path.c_str());
return;
}
file.rewindDirectory();
while (true) {
File entry = file.openNextFile();
if (!entry) {
break;
}
String entryPath = path + "/" + entry.name();
if (entry.isDirectory()) {
entry.close();
deleteRecursive(entryPath);
} else {
entry.close();
SD.remove((char *)entryPath.c_str());
}
yield();
}
SD.rmdir((char *)path.c_str());
file.close();
}
void handleDelete() {
if (server.args() == 0) {
return returnFail("BAD ARGS");
}
String path = server.arg(0);
if (path == "/" || !SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
deleteRecursive(path);
returnOK();
}
void handleCreate() {
if (server.args() == 0) {
return returnFail("BAD ARGS");
}
String path = server.arg(0);
if (path == "/" || SD.exists((char *)path.c_str())) {
returnFail("BAD PATH");
return;
}
if (path.indexOf('.') > 0) {
File file = SD.open((char *)path.c_str(), FILE_WRITE);
if (file) {
file.write(0);
file.close();
}
} else {
SD.mkdir((char *)path.c_str());
}
returnOK();
}
void printDirectory() {
if (!server.hasArg("dir")) {//http://esp32sd.local/list?dir=/
return returnFail("BAD ARGS");
}
String path = server.arg("dir");
if (path != "/" && !SD.exists((char *)path.c_str())) {
return returnFail("BAD PATH");
}
File dir = SD.open((char *)path.c_str());
path = String();
if (!dir.isDirectory()) {
dir.close();
return returnFail("NOT DIR");
}
dir.rewindDirectory();
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, "text/json", "");
WiFiClient client = server.client();
server.sendContent("[");
for (int cnt = 0; true; ++cnt) {
File entry = dir.openNextFile();
if (!entry) {
break;
}
String output;
if (cnt > 0) {
output = ',';
}
output += "{\"type\":\"";
output += (entry.isDirectory()) ? "dir" : "file";
output += "\",\"name\":\"";
output += entry.name();
output += "\"";
output += "}";
server.sendContent(output);
entry.close();
}
server.sendContent("]");
dir.close();
}
void handleNotFound() {
if (hasSD && loadFromSdCard(server.uri())) {
return;
}
String message = "SDCARD Not Detected\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
Serial.print(message);
}
void printDirectory2(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory2(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void setup(void) {
Serial.begin(115200);
// Serial.setDebugOutput(true);
Serial.print("\n");
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to ");
Serial.println(ssid);
// Wait for connection
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
delay(500);
}
if (i == 21) {
Serial.print("Could not connect to");
Serial.println(ssid);
while (1) {
delay(500);
}
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
if (!SD.begin(SS)) {
Serial.println("SD Card initialized.");
hasSD = true;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");//打印SD卡类型
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
if (MDNS.begin(host)) {
MDNS.addService("http", "tcp", 80);
Serial.println("MDNS responder started");
Serial.print("You can now connect to http://");
Serial.print(host);
Serial.println(".local");
}
uploadFile = SD.open("/");
printDirectory2(uploadFile, 0);
server.on("/list", HTTP_GET, printDirectory);//访问SD卡根目录方式:http://esp32sd.local/list?dir=/
server.on("/edit", HTTP_DELETE, handleDelete);//访问SD卡根目录方式:http://esp32sd.local/edit?=/foo.txt
server.on("/edit", HTTP_PUT, handleCreate);
server.on("/edit", HTTP_POST, []() {returnOK();},handleFileUpload);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);//容量信息
}
void loop(void) {
server.handleClient();
delay(2);//allow the cpu to switch to other tasks
}
一般人常规操作,就是直接从串口监视器哪里复制关键信息拷贝到浏览器里面去访问,没错,我也是这么做的。
结果是这样的:
或者这样的;
这样的结果都是一样,不管是IP访问还是域名访问。这英文单词翻译过来的中文意思让人困惑:
不好意思,我英语不好,直接去有道翻译了一下,这困不困惑,感觉就是没有检测到SD卡。是翻译工具出了问题还是官方给的这句话有问题,刚刚开始我就认为是没有检测到SD卡,结果跑去查,烧录其他程序可以识别到,烧录这个示例就识别不到,使用的库还是一样的,怀疑是不是程序的问题,检查了一遍也没发现程序代码有问题,最后发现是访问方式出了问题。
http://esp32sd.local/list?dir=/
没有前端开发的经验的人,估计一上手都会掉进这个坑里面去。
foo.txt
文件作为演示。这里需要借助工具:RestClient工具,选择访问方式:
DELETE
,返回的结果在Response
里面。
http://esp32sd.local/edit?=/foo.txt
以创建一个名为为
perseverance.txt
,还是需要借助RestClient工具,选择请求方式:PUT
,内容:http://esp32sd.local/edit?=/perseverance.txt
返回值:在Response里面看
可以器浏览器在输入查询
http://esp32sd.local/list?dir=/
根目录下的文件会发现,文件一键创建好了,当然在RestClient工具里面也可以,通过GET
方式,查询到一样的结果。