Home / References / ESP32 Library / WebServer Library
Description
The hasResponseHeader()
method is used to check if a specific response header exists in the current HTTP response before it is sent to the client. This method returns a boolean value indicating whether the specified header name has been added to the response using the sendHeader()
method. It’s particularly useful for conditional header logic, debugging HTTP responses, implementing dynamic header management, and ensuring that required headers are properly set before sending responses. The method provides a reliable way to verify header presence without retrieving the header value, making it ideal for validation workflows and security checks where header existence is more important than header content.
Syntax and Usage
The hasResponseHeader()
method has a simple syntax:
- Check header existence:
bool exists = server.hasResponseHeader("Header-Name")
– Returns true if the specified response header exists, false otherwise.
For practical applications and examples of this method, please consult the “Example Code” section on this page. This section provides comprehensive guidance to help you better understand and apply the method effectively.
Arguments
- name (String) – The name of the response header to check for existence. The comparison is case-insensitive, so “Content-Type”, “content-type”, and “CONTENT-TYPE” are all equivalent.
Return Value
The hasResponseHeader()
method returns a bool
value: true
if the specified response header exists in the current response, or false
if the header has not been set. This allows for clean conditional logic when managing response headers dynamically.
Example Code
Conditional Header Management System
This example demonstrates how to use the hasResponseHeader()
method to implement a conditional header management system. The server checks for the existence of various response headers and adds missing ones based on different conditions, ensuring consistent and secure HTTP responses across all endpoints.
How to use this example: Upload this code to your ESP32 and replace the WiFi credentials. After connecting, access the main page at http://ESP32_IP/
to see the header validation dashboard. Test different endpoints to see conditional header logic in action: http://ESP32_IP/api/secure
for security header validation, http://ESP32_IP/api/cached
for caching header checks, and http://ESP32_IP/admin/status
for admin-specific headers. The system will automatically add missing headers and report which headers were found or added.
For more ESP32 development resources and tutorials, visit the All About ESP32 Resources Hub on AvantMaker.com
/*
* Author: Avant Maker
* Date: June 18, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This example demonstrates how to use the hasResponseHeader() method to
* implement a conditional header management system. The server checks for
* the existence of various response headers and adds missing ones based on
* different conditions, ensuring consistent and secure HTTP responses
* across all endpoints.
*
* How to use this example:
* Upload this code to your ESP32 and replace the WiFi credentials.
* After connecting, access the main page at http://ESP32_IP/ to see the
* header validation dashboard. Test different endpoints to see conditional
* header logic in action: http://ESP32_IP/api/secure for security header
* validation, http://ESP32_IP/api/cached for caching header checks, and
* http://ESP32_IP/admin/status for admin-specific headers. The system will
* automatically add missing headers and report which headers were found or added.
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com, your premier destination for all things
* DIY, AI, IoT, Smart Home, and STEM projects. We are dedicated
* to empowering makers, learners, and enthusiasts with
* the resources they need to bring their nnovative ideas to life.
*/
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
WebServer server(80);
// Header validation statistics
struct HeaderValidationStats {
unsigned long totalValidations = 0;
unsigned long headersAdded = 0;
unsigned long headersFound = 0;
String lastValidatedEndpoint = "";
} stats;
// Function to ensure security headers are present
void ensureSecurityHeaders() {
String endpoint = "Security Headers";
stats.lastValidatedEndpoint = endpoint;
stats.totalValidations++;
Serial.println("=== Security Header Validation ===");
// Check and add X-Content-Type-Options if missing
if (!server.hasResponseHeader("X-Content-Type-Options")) {
server.sendHeader("X-Content-Type-Options", "nosniff");
stats.headersAdded++;
Serial.println("✓ Added missing X-Content-Type-Options header");
} else {
stats.headersFound++;
Serial.println("✓ X-Content-Type-Options header already exists");
}
// Check and add X-Frame-Options if missing
if (!server.hasResponseHeader("X-Frame-Options")) {
server.sendHeader("X-Frame-Options", "DENY");
stats.headersAdded++;
Serial.println("✓ Added missing X-Frame-Options header");
} else {
stats.headersFound++;
Serial.println("✓ X-Frame-Options header already exists");
}
// Check and add X-XSS-Protection if missing
if (!server.hasResponseHeader("X-XSS-Protection")) {
server.sendHeader("X-XSS-Protection", "1; mode=block");
stats.headersAdded++;
Serial.println("✓ Added missing X-XSS-Protection header");
} else {
stats.headersFound++;
Serial.println("✓ X-XSS-Protection header already exists");
}
// Check and add Strict-Transport-Security if missing
if (!server.hasResponseHeader("Strict-Transport-Security")) {
server.sendHeader("Strict-Transport-Security", "max-age=31536000");
stats.headersAdded++;
Serial.println("✓ Added missing Strict-Transport-Security header");
} else {
stats.headersFound++;
Serial.println("✓ Strict-Transport-Security header already exists");
}
}
// Function to ensure caching headers are properly set
void ensureCachingHeaders(bool shouldCache) {
String endpoint = "Caching Headers";
stats.lastValidatedEndpoint = endpoint;
stats.totalValidations++;
Serial.println("=== Caching Header Validation ===");
if (shouldCache) {
if (!server.hasResponseHeader("Cache-Control")) {
server.sendHeader("Cache-Control", "public, max-age=3600");
stats.headersAdded++;
Serial.println("✓ Added Cache-Control header for caching");
} else {
stats.headersFound++;
Serial.println("✓ Cache-Control header already exists");
}
if (!server.hasResponseHeader("ETag")) {
server.sendHeader("ETag", "\"esp32-" + String(millis()) + "\"");
stats.headersAdded++;
Serial.println("✓ Added ETag header for caching");
} else {
stats.headersFound++;
Serial.println("✓ ETag header already exists");
}
} else {
if (!server.hasResponseHeader("Cache-Control")) {
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
stats.headersAdded++;
Serial.println("✓ Added Cache-Control header for no-caching");
} else {
stats.headersFound++;
Serial.println("✓ Cache-Control header already exists");
}
if (!server.hasResponseHeader("Pragma")) {
server.sendHeader("Pragma", "no-cache");
stats.headersAdded++;
Serial.println("✓ Added Pragma header for no-caching");
} else {
stats.headersFound++;
Serial.println("✓ Pragma header already exists");
}
}
}
// Function to add application-specific headers
void ensureApplicationHeaders() {
String endpoint = "Application Headers";
stats.lastValidatedEndpoint = endpoint;
stats.totalValidations++;
Serial.println("=== Application Header Validation ===");
if (!server.hasResponseHeader("X-Powered-By")) {
server.sendHeader("X-Powered-By", "ESP32 Arduino Core");
stats.headersAdded++;
Serial.println("✓ Added X-Powered-By header");
} else {
stats.headersFound++;
Serial.println("✓ X-Powered-By header already exists");
}
if (!server.hasResponseHeader("X-Server-Info")) {
server.sendHeader("X-Server-Info", "ESP32 Conditional Header Manager");
stats.headersAdded++;
Serial.println("✓ Added X-Server-Info header");
} else {
stats.headersFound++;
Serial.println("✓ X-Server-Info header already exists");
}
}
void handleRoot() {
// Add some initial headers
server.sendHeader("X-Request-ID", String(millis()));
server.sendHeader("X-Response-Time", String(micros()));
// Use conditional header management
ensureSecurityHeaders();
ensureApplicationHeaders();
ensureCachingHeaders(false); // Don't cache main page
String html = "<!DOCTYPE html><html><head>";
html += "<title>AvantMaker ESP32 Conditional Header Manager</title>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<style>";
html += "body{font-family:Arial,sans-serif;margin:20px;background:#f0f8ff;}";
html += ".container{max-width:1000px;margin:0 auto;background:white;padding:30px;border-radius:12px;box-shadow:0 6px 20px rgba(0,0,0,0.1);}";
html += ".header-status{background:#e8f5e8;padding:20px;border-radius:8px;margin:20px 0;border-left:5px solid #28a745;}";
html += ".stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:15px;margin:25px 0;}";
html += ".stat-card{background:linear-gradient(135deg,#4CAF50 0%,#45a049 100%);color:white;padding:25px;border-radius:10px;text-align:center;}";
html += ".stat-number{font-size:2.5em;font-weight:bold;margin-bottom:8px;}";
html += ".stat-label{font-size:0.95em;opacity:0.9;}";
html += ".test-section{background:#fff3cd;padding:25px;border-radius:8px;margin:20px 0;border:1px solid #ffeaa7;}";
html += ".btn{background:#007bff;color:white;padding:14px 22px;border:none;border-radius:6px;text-decoration:none;margin:8px;display:inline-block;transition:all 0.3s;}";
html += ".btn:hover{background:#0056b3;transform:translateY(-2px);}";
html += ".btn.success{background:#28a745;} .btn.success:hover{background:#1e7e34;}";
html += ".btn.warning{background:#ffc107;color:#212529;} .btn.warning:hover{background:#e0a800;}";
html += ".btn.info{background:#17a2b8;} .btn.info:hover{background:#138496;}";
html += ".header-list{background:#f8f9fa;padding:20px;border-radius:8px;margin:15px 0;}";
html += ".header-item{background:#e9ecef;margin:8px 0;padding:12px;border-radius:6px;font-family:monospace;}";
html += "</style></head><body>";
html += "<div class='container'>";
html += "<h1>🛡️ AvantMaker ESP32 Conditional Header Manager</h1>";
html += "<p>This system demonstrates the <code>hasResponseHeader()</code> method by implementing intelligent conditional header management.</p>";
// Display current validation status
html += "<div class='header-status'>";
html += "<h3>✅ Header Validation Complete</h3>";
html += "<p>All required headers were validated and missing headers were automatically added.</p>";
html += "<p><strong>Total Response Headers:</strong> " + String(server.responseHeaders()) + "</p>";
html += "<p><strong>Last Validation:</strong> " + stats.lastValidatedEndpoint + "</p>";
html += "</div>";
// Display statistics
html += "<div class='stats-grid'>";
html += "<div class='stat-card'><div class='stat-number'>" + String(stats.totalValidations) + "</div><div class='stat-label'>Total Validations</div></div>";
html += "<div class='stat-card'><div class='stat-number'>" + String(stats.headersFound) + "</div><div class='stat-label'>Headers Found</div></div>";
html += "<div class='stat-card'><div class='stat-number'>" + String(stats.headersAdded) + "</div><div class='stat-label'>Headers Added</div></div>";
float successRate = (stats.totalValidations > 0) ? (float)(stats.headersFound + stats.headersAdded) / (stats.headersFound + stats.headersAdded + stats.totalValidations) * 100 : 100;
html += "<div class='stat-card'><div class='stat-number'>" + String(successRate, 1) + "%</div><div class='stat-label'>Validation Success</div></div>";
html += "</div>";
// Show current headers
html += "<div class='header-list'>";
html += "<h3>📋 Current Response Headers</h3>";
for (int i = 0; i < server.responseHeaders(); i++) {
String headerName = server.responseHeaderName(i);
String headerValue = server.responseHeader(i);
html += "<div class='header-item'>" + headerName + ": " + headerValue + "</div>";
}
html += "</div>";
// Test endpoints
html += "<div class='test-section'>";
html += "<h3>🧪 Test Conditional Header Logic</h3>";
html += "<p>Click these endpoints to see how <code>hasResponseHeader()</code> enables intelligent header management:</p>";
html += "<a href='/api/secure' class='btn success'>Security API (Auto-Security Headers)</a>";
html += "<a href='/api/cached' class='btn info'>Cached API (Auto-Cache Headers)</a>";
html += "<a href='/admin/status' class='btn warning'>Admin Status (Custom Headers)</a>";
html += "<a href='/stats/reset' class='btn'>Reset Statistics</a>";
html += "</div>";
// Usage instructions
html += "<h3>📖 How It Works</h3>";
html += "<ul>";
html += "<li>The system uses <code>hasResponseHeader()</code> to check if required headers exist</li>";
html += "<li>Missing headers are automatically added with appropriate values</li>";
html += "<li>Different endpoints have different header requirements</li>";
html += "<li>All header validation activities are logged to Serial monitor</li>";
html += "<li>Statistics track the effectiveness of the validation system</li>";
html += "</ul>";
html += "<h3>📊 System Information</h3>";
html += "<p>Free Heap: " + String(ESP.getFreeHeap()) + " bytes | ";
html += "Uptime: " + String(millis()/1000) + "s | ";
html += "WiFi Signal: " + String(WiFi.RSSI()) + " dBm</p>";
html += "</div></body></html>";
server.send(200, "text/html", html);
Serial.println("Main page served with " + String(server.responseHeaders()) + " headers");
}
void handleSecureAPI() {
// Pre-add one security header
server.sendHeader("X-Content-Type-Options", "nosniff");
// Let the system add the rest conditionally
ensureSecurityHeaders();
String json = "{";
json += "\"message\":\"Secure API with conditional security headers\",";
json += "\"securityValidation\":\"completed\",";
json += "\"totalHeaders\":" + String(server.responseHeaders()) + ",";
json += "\"headersFound\":" + String(stats.headersFound) + ",";
json += "\"headersAdded\":" + String(stats.headersAdded) + ",";
json += "\"timestamp\":" + String(millis());
json += "}";
server.send(200, "application/json", json);
Serial.println("Secure API served with conditional security headers");
}
void handleCachedAPI() {
// Pre-add Cache-Control header
server.sendHeader("Cache-Control", "public, max-age=1800");
// Let the system handle other caching headers conditionally
ensureCachingHeaders(true);
ensureApplicationHeaders();
String response = "Cached API Response\n\n";
response += "Cache validation completed\n";
response += "Headers found: " + String(stats.headersFound) + "\n";
response += "Headers added: " + String(stats.headersAdded) + "\n";
response += "Total headers: " + String(server.responseHeaders()) + "\n";
server.send(200, "text/plain", response);
Serial.println("Cached API served with conditional caching headers");
}
void handleAdminStatus() {
// Add some admin-specific headers first
server.sendHeader("X-Admin-Access", "authorized");
server.sendHeader("X-Admin-Level", "full");
// Then ensure standard headers
ensureSecurityHeaders();
ensureApplicationHeaders();
// Check if specific admin headers exist
bool hasAdminAccess = server.hasResponseHeader("X-Admin-Access");
bool hasAdminLevel = server.hasResponseHeader("X-Admin-Level");
bool hasServerInfo = server.hasResponseHeader("X-Server-Info");
String status = "Admin Status Report\n\n";
status += "=== Header Existence Check ===\n";
status += "X-Admin-Access exists: " + String(hasAdminAccess ? "YES" : "NO") + "\n";
status += "X-Admin-Level exists: " + String(hasAdminLevel ? "YES" : "NO") + "\n";
status += "X-Server-Info exists: " + String(hasServerInfo ? "YES" : "NO") + "\n\n";
status += "=== Statistics ===\n";
status += "Total validations: " + String(stats.totalValidations) + "\n";
status += "Headers found: " + String(stats.headersFound) + "\n";
status += "Headers added: " + String(stats.headersAdded) + "\n";
status += "Current response headers: " + String(server.responseHeaders()) + "\n";
server.send(200, "text/plain", status);
Serial.println("Admin status served with role-specific headers");
}
void handleResetStats() {
stats.totalValidations = 0;
stats.headersAdded = 0;
stats.headersFound = 0;
stats.lastValidatedEndpoint = "";
server.send(200, "text/plain", "Header validation statistics reset!\n\nGo back to: http://" + WiFi.localIP().toString());
Serial.println("Header validation statistics reset");
}
void setup() {
Serial.begin(115200);
Serial.println("Starting ESP32 Conditional Header Manager...");
// Connect to WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("WiFi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Set up route handlers
server.on("/", handleRoot);
server.on("/api/secure", handleSecureAPI);
server.on("/api/cached", handleCachedAPI);
server.on("/admin/status", handleAdminStatus);
server.on("/stats/reset", handleResetStats);
// Start server
server.begin();
Serial.println("HTTP server started");
Serial.println("Conditional header manager available at: http://" + WiFi.localIP().toString());
Serial.println("Monitor Serial output for header validation logs");
}
void loop() {
server.handleClient();
// Optional: Print periodic statistics
static unsigned long lastPrint = 0;
if (millis() - lastPrint > 60000) { // Every 60 seconds
lastPrint = millis();
if (stats.totalValidations > 0) {
Serial.println("📊 Header Validation Statistics:");
Serial.println(" Total validations: " + String(stats.totalValidations));
Serial.println(" Headers found: " + String(stats.headersFound));
Serial.println(" Headers added: " + String(stats.headersAdded));
Serial.println(" Success rate: " + String((float)(stats.headersFound + stats.headersAdded) / stats.totalValidations * 100, 1) + "%");
}
}
}
ESP32 Library Index
- ESP32 WiFi Library
- ESP32 WiFiClient Library
- ESP32 HTTPClient Library
- ESP32 WiFiClientSecure Library
- ESP32 AsyncUDP Librarry
- ESP32 WebServer Library
- Server Operation
- Client Hnadling
- Routing and Handlers
- Authentication
- Request Information
- Request Header Management
- Response Information
- Server Configuration
- Which ESP32 Boards are Recommended for Learners
- How to Copy Codes from AvantMaker.com
- What is SPIFFS and how to upload files to it?
- What is LIttleFS and how to upload files to it?
Ready to experiment and explore more about ESP32? Visit our website’s All About ESP32 Resources Hub, packed with tutorials, guides, and tools to inspire your maker journey. Experiment, explore, and elevate your skills with everything you need to master this powerful microcontroller platform!