I combined two different codes together, a captive portal and a SD card web server. I encountered a problem which the website in the SD card doesn't load when I connect to the AP (captive portal page). Here's the code..

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "./DNSServer.h"
#include <SPI.h>
#include <SD.h>

const byte        DNS_PORT = 53;          // Capture DNS requests on port 53
IPAddress         apIP(10, 10, 10, 1);    // Private network for server
DNSServer         dnsServer;              // Create the DNS object
ESP8266WebServer server(80);
String responseHTML = ""
                      "<html><head><title>Captive Portal Test</title>"
                      "img{ min-height:100%; min-width:100%;height:auto;width:auto;"
                      "position:absolute;top:-100%; bottom:-100%;left:-100%; right:-100%;"
                      "margin:auto;}</style></head><body><img src='test.png' /><h1>TEST</h1></body></html>";

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()) {

  return true;

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);

void setup(void) {
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  WiFi.softAP("TEST AP");
  dnsServer.start(DNS_PORT, "*", apIP);
  server.onNotFound([]() {
  server.send(200, "text/html", responseHTML);


  if (SD.begin(SS)) {
    hasSD = true;

void loop(void) {

This code replies the responseHTML as a Captive portal page which immediately pop-ups when I connect to the AP:

server.onNotFound([]() {
      server.send(200, "text/html", responseHTML);

The void handleNotFound() handles the page/file request from the browser but if I use it on


The captive portal won't show but if I type the server address, the page will appear. What seems to be the problem?

1 Answer 1


Remove hasSD && from void handleNotFound() function.

It worked for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.