ESP8266WebServer - How To Respond JQuery GET Request (HTTP_OPTIONS)

Ok, I came up with a solution as I was typing this.
So my problem is solved but I thought I would share in the event that someone else is trying to figure this out.
Also, as I have ‘solved’ this via the proof by exhaustion method I would appreciate any input/suggestions from anyone that knows what they are doing - 'cause I barely do :slight_smile:

I am experimenting with a recently purchased NodeMCU ESP8266
I want to have it publish several web service methods to manage a connected LED
You know, the typical stuff: 1) turn the LED on 2) turn the LED off 3) get LEDs current state

I have a working example, but it needs some help
I can execute all of the methods by directly entering URLs into a browser
But when I try to execute these methods via a Jquery GET they do not work properly

The reason is that the JQuery GET (in Chrome at least) is performing an HTTP_OPTIONS request before performing the GET.

As I understand the OPTIONS request it is used as a security device and the server is expected to respond with a summary of that allowed request methods. The client will perform this request BEFORE a GET/POST request when a cross domain (CORS) query is performed and a ‘positive’ response tells the client that calling the desired GET/POST is allowed and safe.

So, the server needs to publish a HTTP_OPTIONS method that confirms that the GET/POST is allowed. The HTTP_OPTIONS response should have no content but does have to set the correct headers (see the server.setHeader(…) calls in the setupHttpServer() method in the code below)

Server Code - on the ESP8266

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

//
// ESP8266 Web Server / LED Driver Example : https://learn.sparkfun.com/tutorials/esp8266-thing-hookup-guide/example-sketch-ap-web-server
// Connecting with WPA:  https://www.arduino.cc/en/Tutorial/ConnectWithWPA
//


/////////////////////
// Pin Definitions //
/////////////////////
const int LED_PIN = D7;

int ledState = LOW;


ESP8266WebServer server(80);

//
// Setup WiFi Configuration
//
void setupWiFi()
{
  WiFi.begin("VaporNet","Get49han");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print("Connected! Open http://");
  Serial.print(WiFi.localIP());
  Serial.println(" in your browser");
}

//
// Setup Hardware Configurations
//
void setupHardware()
{
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
}

//
// Setup HTTP Server
//
void setupHttpServer()
{

  server.begin();
  
  //
  // LED OFF Methods
  //
  server.on("/ledoff", HTTP_GET, []() {
    setLedOff();
  });
  
  server.on("/ledoff", HTTP_OPTIONS, []() {
    server.sendHeader("access-control-allow-credentials", "false");
    server.sendHeader("access-control-allow-headers", "x-requested-with");
    server.sendHeader("access-control-allow-methods", "GET,OPTIONS");

    server.send(204);
  });

  //
  // LED ON Methods
  //
  server.on("/ledon", HTTP_GET, []() {
    setLedOn();
  });
  
  server.on("/ledon", HTTP_OPTIONS, []() {
    server.sendHeader("access-control-allow-credentials", "false");
    server.sendHeader("access-control-allow-headers", "x-requested-with");
    server.sendHeader("access-control-allow-methods", "GET,OPTIONS");

    server.send(204);
  });
  
  //
  // Info Methods
  //
  server.on("/info", HTTP_GET, []() {
    sendInfo();
  });
  
  server.on("/info", HTTP_OPTIONS, []() {
    server.sendHeader("access-control-allow-credentials", "false");
    server.sendHeader("access-control-allow-headers", "x-requested-with");
    server.sendHeader("access-control-allow-methods", "GET,OPTIONS");

    server.send(204);
  });
}


//
// Main Setup
//
void setup() 
{
  setupHardware();
  setupWiFi();
  setupHttpServer();
}


//
// Generates response for LED OFF Request
//
void setLedOff()
{
    ledState = LOW;
    digitalWrite(LED_PIN, ledState);
  
    String json = "{";
    json += "\"ledstate\":" + String(ledState ? "ON" : "OFF");
    json += "}";
    
    server.send(200, "text/json", json);
    json = String();   
}

//
// Generates response for LED ON Request
//
void setLedOn()
{
    ledState = HIGH;
    digitalWrite(LED_PIN, ledState);
    
    String json = "{";
    json += "\"ledstate\":" + String(ledState ? "ON" : "OFF");
    json += "}";
    
    server.send(200, "text/json", json);
    json = String();    
}

//
// Generates response for Info Request
//
void sendInfo()
{    
    String json = "{";
    
    json += "\"ssid\":" + String(WiFi.SSID()) + ",";
    json += "\"ip\":" ;
    json += WiFi.localIP().toString();
    json += ",";
    json += "\"mac\":" + String(WiFi.macAddress()) + ",";
    json += "\"ledstate\":" + String(ledState ? "ON" : "OFF");
    json += "}";
    
    server.send(200, "text/json", json);
    json = String();  
}

//
// Main Loop
//
void loop() 
{
  server.handleClient();
}

Client Code - ESP8266_Test.html

<html>
<head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>

    <script>

        function cmd(arg) {  
            url = "http://192.168.1.8/"+arg
            $("#console").html($("#console").html()+"
Requesting..."+url);
 
            $.get(url, function( data ) {
                $("#console").html($("#console").html()+"
Response<pre>"+data+"</pre>");
              });
        }

    </script>
</head>
<body>

    <button onclick="return cmd('ledon')" form="form1" value="Submit">LED ON</button>
    <button onclick="return cmd('ledoff')" form="form1" value="Submit">LED OFF</button>
    <button onclick="return cmd('info')" form="form1" value="Submit">Info</button>
 


    <div id="console" name="console" width=200 height=300>Ready.</div>
 
</body>
</html>

Thanks for your post It's very usefully.
Bye

This is really helpful. Thanks.
PS You can use ESP8266mDNS library for addressing the esp8266.