Css file doesn't work off server: Firefox might be giving me a clue

I am really new to web design. I have an ESP32 functioning as a web socket server.

I have a weird situation where my web pages work fine locally (i.e. double click on the file) but when I serve them off my ESP32 the css is ignored. I know the exact same files are being served up locally or off the ESP32 because I compared each of the html, css, and js against the originals and what appears in the browser in debug mode so the issue is almost certainly with the file contents. Also because this usually comes up, I have cleared caches, etc…

In development mode I get no errors from Opera, Chrome, or Edge, but Firefox says

The stylesheet http://192.168.1.232/styles.css was not loaded because its MIME type, “text/html”, is not “text/css”. 192.168.1.232

The script from “http://192.168.1.232/ESP-UI.js” was loaded even though its MIME type (“text/html”) is not a valid JavaScript MIME type. 192.168.1.2

I suspect this is a clue: perhaps the MIME type needs to be specified by the server but is known locally. The thing is, I have specified the type (see below). I pretty much cut and pasted these from various examples. (hence the commented out lines. What am I doing wrong?

*** and additional observation: If I start Firefox and load my page then invoke the debugger, the style sheets seem to work even though I have the same errors logged ****

My html file header is (sorry it doesn’t seem to work when I include my code :frowning:
but these are the relevant lines

<script type="text/javascript" src="ESP-UI.js"></script>
<title>ESP32 Servertitle>
-->

Thanks

1 Like

Hi,

I’m shooting in the dark a little here, but the issue could be due to your ESP32 server not setting the correct MIME types for the files it serves.

I’m not talking about specifying a type="text/javascript" attribute on your script tag (this is more or less redundant nowadays), rather how the server is sending the files.

Using the ESP32 WebServer library, you can specifying the MIME type something like this (untested):

server.on("/styles.css", HTTP_GET, []() {
  File file = SPIFFS.open("/styles.css", "r");
  server.streamFile(file, "text/css");
  file.close();
});

How are you serving the files?

1 Like

Thank you for the reply!

I thought I had actually replied to my post because late yesterday I discovered that was, indeed the issue. I am not using Arduino, but ESP-IDF and many of the examples are opaque to say the least.

I observed that favicon.ico was not being served and decided to solve that. I determined that serving an icon required setting the MIME type via the server, investigated further and figured out this was generally true.

I was misled because the error was telling me something was wrong even though I explicitly stated it (text/css) in my scripts. I also find it odd that Firefox pointed out the error while none of the other browsers did.

Thanks again for your help.

1 Like

I’m glad you got it sorted :slight_smile:

For the sake of posterity, would you mind posting the code which worked for you? (just the snippet to serve the CSS)

It might help someone else.

1 Like

sure but it is a work in process.

struct resp_type {
    char *ext;
    char *type;
};

struct resp_type FileRespTypes[] = {
    {.ext = "html",
    .type = "text/html"
    },
    
    {.ext = "css",
    .type = "text/css"
    },

    {.ext = "js",
    .type = "text/javascript"
    },

    {.ext = "ico",
    .type = "image/x-icon"
    },

};



esp_err_t root_get_handler( httpd_req_t *req ) {
char filename[100] = "Not found";
int i;
int rv = ESP_FAIL;
//
// Change URI request to the actual file name
//
    for( i = 0; i < sizeof( URI_Get_List)/sizeof( struct URI_File_Lookup); i++ ) {
        if( strcmp( URI_Get_List[i].uriname, req->uri) == 0 ) {
            strcpy( filename, "/spiffs/" );                 //All files are in spiffs
            strcat( filename, URI_Get_List[i].filename );
            rv = ESP_OK;
            break;
        }
    }

    ESP_LOGI( TAG, "Handleing URI");

    if( rv != ESP_OK ) {
        ESP_LOGE( TAG, "URI not found: %s", req->uri );
        return( rv );
    }

    if( URI_Get_List[i].type == websocket ) return( websocket_handler( req ));

struct  stat    status;
FILE    *fp;

    if ( stat( filename, &status )) {
        ESP_LOGE(TAG, "%s not found", filename);
        return( ESP_ERR_NOT_FOUND );
    }

    fp = fopen(filename, "r");

bool    failed = false;
char    *chunk = malloc( SCRATCH_BUFSIZE );
char    *extension = strchr( filename, '.') + 1; //start of file extension
char    *resp_type = "text/plain";
size_t  bytesread, bytesremaining;

    for( i = 0; i < (sizeof(FileRespTypes )/ sizeof(struct resp_type )); i++ ) {
        if( strcasecmp( extension, FileRespTypes[i].ext) == 0)
            resp_type = FileRespTypes[i].type;
    }

    ESP_LOGW( "Send web page", "%s, type %s, size %d", filename, resp_type, (int) status.st_size );
    httpd_resp_set_type(req, resp_type );

    bytesremaining = status.st_size;
    do {
        bytesread = bytesremaining >= SCRATCH_BUFSIZE ? SCRATCH_BUFSIZE : bytesremaining;
        bytesread = fread( chunk, 1, bytesread, fp );       //Read into scratch

//        printf( "\nRead %d remaining %d ", (int) bytesread, bytesremaining );
        if (bytesread > 0) { //Send the buffer contents as HTTP response chunk 
            if (httpd_resp_send_chunk(req, chunk, bytesread ) != ESP_OK) {
                failed = true;
            }
        }
        bytesremaining -= bytesread;
    } while ((bytesremaining != 0) && ( !failed ));

    free( chunk );
    fclose(fp);
    httpd_resp_sendstr_chunk(req, NULL); //Finish/Abort sending file 

    if( failed  ) {  //Failed
        ESP_LOGE(TAG, "Sending %s failed!", filename );
        httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
        return( ESP_FAIL );
    }
    return( ESP_OK );
}

Thanks for that! It’s a nice approach to dynamically handle MIME types and serve files with chunking.

Note that this won’t work on filenames with multiple dots, like app.min.js.
Better to find the last dot in the filename instead. Although some files do have two extensions like .tar.gz.

1 Like