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

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


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

  • 视频教程

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

在这里插入图片描述

  • 看到上面示例的前提,先把开发板选择为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 <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPI.h>
#include <SD.h>
#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卡,结果跑去查,烧录其他程序可以识别到,烧录这个示例就识别不到,使用的库还是一样的,怀疑是不是程序的问题,检查了一遍也没发现程序代码有问题,最后发现是访问方式出了问题。

正确的访问方式

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

在这里插入图片描述

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

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

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

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

在这里插入图片描述

返回结果
在这里插入图片描述

  1. 浏览器再去访问:http://esp32sd.local/list?dir=/,会发现,foo.txt文件已经被删除了。
    在这里插入图片描述
  2. 在SD卡根目录下创建一个文件。

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

在这里插入图片描述

返回值:在Response里面看

在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值