上一篇貼文的網站伺服器程式,需要手動處理檔案路徑和內容類型,本單元將加入自動判斷資源內容類型,並且自動傳送指定路徑的資源的程式。
自動設定資源的內容類型
底下的getContentType()自訂函式,可自動判別檔案的內容類型。此函式取自ESP8266WebServer程式庫裡的FSBrowser原始碼,它接收一個檔名(filename)參數,並傳回字串格式的內容類型資料:
String getContentType(String filename){
if(server.hasArg("download")) return "application/octet-stream";
else if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
else if(filename.endsWith(".css")) return "text/css";
else if(filename.endsWith(".js")) return "application/javascript";
else if(filename.endsWith(".png")) return "image/png";
else if(filename.endsWith(".gif")) return "image/gif";
else if(filename.endsWith(".jpg")) return "image/jpeg";
else if(filename.endsWith(".ico")) return "image/x-icon";
else if(filename.endsWith(".xml")) return "text/xml";
else if(filename.endsWith(".pdf")) return "application/x-pdf";
else if(filename.endsWith(".zip")) return "application/x-zip";
else if(filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
此函式透過String物件的endsWith()方法,檢查字串是否以指定的內容結尾。例如:

因此,假若檔名路徑的結尾是“.htm”或“.html”,此函式將傳回“text/html”內容類型。
自動處理檔案路徑
底下「處理檔案讀取」的handleFileRead()函式,也是修改自FSBrowser原始碼。此函式接收一個path(路徑)參數,如果參數值為“/”,程式將把路徑改成“/index.htm”,然後透過SPIFFS物件的exists()方法判斷此檔案是否存在於快閃記憶體,若有,則執行server.streamFile()把檔案傳給用戶端。

上面的程式同樣執行String物件的endsWith()方法確認路徑:

加入以上兩個新程式片段之後,請把處理根路徑的事件程式,改寫在處理「不存在的」路徑的函式裡面:

完整的程式碼如下:
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>
const char ssid[] = "你的WiFi網路SSID";
const char pass[] = "你的WiFi密碼";
const char* host = "jarvis";
ESP8266WebServer server(80);
String getContentType(String filename){
if(server.hasArg("download")) return "application/octet-stream";
else if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
else if(filename.endsWith(".css")) return "text/css";
else if(filename.endsWith(".js")) return "application/javascript";
else if(filename.endsWith(".png")) return "image/png";
else if(filename.endsWith(".gif")) return "image/gif";
else if(filename.endsWith(".jpg")) return "image/jpeg";
else if(filename.endsWith(".ico")) return "image/x-icon";
else if(filename.endsWith(".xml")) return "text/xml";
else if(filename.endsWith(".pdf")) return "application/x-pdf";
else if(filename.endsWith(".zip")) return "application/x-zip";
else if(filename.endsWith(".gz")) return "application/x-gzip";
return "text/plain";
}
bool handleFileRead(String path){
Serial.println("handleFileRead: " + path); // 在序列埠顯示路徑
if (path.endsWith("/")) {
path += "index.htm";
}
String contentType = getContentType(path);
if (SPIFFS.exists(path)){
File file = SPIFFS.open(path, "r");
server.streamFile(file, contentType);
file.close();
return true;
}
return false;
}
void setup( ){
Serial.begin(115200);
SPIFFS.begin(); // 啟用SPIFFS檔案系統
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
IPAddress ip = WiFi.localIP();
if (!MDNS.begin(host, ip)) {
Serial.println("Error setting up MDNS responder!");
while(1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
server.onNotFound([](){
if (!handleFileRead(server.uri())) {
server.send(404, "text/plain", "FileNotFound");
}
});
server.begin();
Serial.println("HTTP server started");
MDNS.setInstanceName("Cubie's ESP8266");
MDNS.addService("http", "tcp", 80);
}
void loop( ){
server.handleClient();
}
重新編譯、上傳此程式碼,再連結到“jarvis.local”,即可看見如下的圖文網頁:

未完…待續。

老师您好,对于“請把處理根路徑的事件程式,改寫在處理「不存在的」路徑的函式裡面”这句话我不是很理解,可以请你解释一下,为什么浏览器输入IP地址后,会触发server.onNotFound吗?
对,请比较「在ESP8266的SPIFFS檔案系統存放網頁檔案(一)」这篇文章的代码,包含处理根路径请求的事件:
server.on(“/”, rootRouter);
server.on(“/index.htm”, rootRouter);
这篇文章的代码并没有这两个陈述,因此所有路径请求都会触发server.onNotFound事件。
thanks,
jeffrey
老师,您好,我还想问一下下面这个代码(省略了一点内容)
File message_file=SFIFFS.open(“data.txt”);
medium_message+=char(message_file.read());
return medium_message;
最后返回的 medium_message的内容就是data.txt这个文件里的内容吗?是字符型的?
对,因为已经转成char型。
thanks,
jeffrey
老师,
File file=SFIFFS.open(“data.txt”);
message+=char(file.read());
在这个基础上,如果我将message的内容通过server.send(200, “text/html”, “message”);发给浏览器后,浏览器的IP地址是会变成http/…/…/…/…/data.txt吗?
如果我没有设置server.on(“/data.txt”, rootRouter);,是不是也会触发server.onNotFound?
负责处理网页路径请求的是server.on(),如果没有设置的话,就会触发server.onNotFound。
thanks,
jeffrey