Arduino ESP32 SDWebServer示例程序正确访问方式

Arduino ESP32 SDWebServer示例程序正确访问方式


估计也会有像我这样直接调用示例程序来跑,发现无法访问的人应该还会有,官方示例给的有点太随意,有些注释让人困惑。

  • 视频教程

SDWebServer例程修改使用记录(ESP32)文件服务器

Arduino ESP32 SDWebServer示例程序正确访问方式_第1张图片

  • 看到上面示例的前提,先把开发板选择为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
}

示例程序编译-上传这样的常规操作就不在这里演示了。

  • 程序烧录完后,看到串口打印信息如下:
    Arduino ESP32 SDWebServer示例程序正确访问方式_第2张图片

一般人常规操作,就是直接从串口监视器哪里复制关键信息拷贝到浏览器里面去访问,没错,我也是这么做的。
结果是这样的:

Arduino ESP32 SDWebServer示例程序正确访问方式_第3张图片

或者这样的;

Arduino ESP32 SDWebServer示例程序正确访问方式_第4张图片

这样的结果都是一样,不管是IP访问还是域名访问。这英文单词翻译过来的中文意思让人困惑:

Arduino ESP32 SDWebServer示例程序正确访问方式_第5张图片

不好意思,我英语不好,直接去有道翻译了一下,这困不困惑,感觉就是没有检测到SD卡。是翻译工具出了问题还是官方给的这句话有问题,刚刚开始我就认为是没有检测到SD卡,结果跑去查,烧录其他程序可以识别到,烧录这个示例就识别不到,使用的库还是一样的,怀疑是不是程序的问题,检查了一遍也没发现程序代码有问题,最后发现是访问方式出了问题。

正确的访问方式

  1. 查看SD卡根目录文件浏览器地址栏输入:http://esp32sd.local/list?dir=/

Arduino ESP32 SDWebServer示例程序正确访问方式_第6张图片

没有前端开发的经验的人,估计一上手都会掉进这个坑里面去。

  1. 删除目录下的foo.txt文件作为演示。

这里需要借助工具:RestClient工具,选择访问方式:DELETE,返回的结果在Response里面。

http://esp32sd.local/edit?=/foo.txt

Arduino ESP32 SDWebServer示例程序正确访问方式_第7张图片

返回结果
Arduino ESP32 SDWebServer示例程序正确访问方式_第8张图片

  1. 浏览器再去访问:http://esp32sd.local/list?dir=/,会发现,foo.txt文件已经被删除了。
    Arduino ESP32 SDWebServer示例程序正确访问方式_第9张图片
  2. 在SD卡根目录下创建一个文件。

以创建一个名为为perseverance.txt,还是需要借助RestClient工具,选择请求方式:PUT,内容:http://esp32sd.local/edit?=/perseverance.txt

Arduino ESP32 SDWebServer示例程序正确访问方式_第10张图片

返回值:在Response里面看

Arduino ESP32 SDWebServer示例程序正确访问方式_第11张图片

可以器浏览器在输入查询http://esp32sd.local/list?dir=/根目录下的文件会发现,文件一键创建好了,当然在RestClient工具里面也可以,通过GET方式,查询到一样的结果。

Arduino ESP32 SDWebServer示例程序正确访问方式_第12张图片
Arduino ESP32 SDWebServer示例程序正确访问方式_第13张图片

你可能感兴趣的:(Arduino,ESP32,零基础入门实例教程,Arduino,SD卡,SDWebServer)