Skip to content

404 Error when serving Kobweb 404 Page on Ktor Server #676

@EchoEllet

Description

@EchoEllet

Unexpected 404 Error when serving Kobweb 404 Page on Ktor Server.

  • Kobweb libs version: 0.20.4
  • Ktor version: 3.1.1

Description

I'm trying to get the Ktor server working with the Kobweb static site.

This issue should have low priority as the workaround works as expected.

The Kobweb 404 page:

// pages/404.kt

@Page
@Composable
fun NotFoundPage() {
    PageLayout("Page not found") {
        Text("This page is not found or it might have been moved somewhere else.")
    }
}

Configured the Ktor server to respond with the file content of this page:

install(StatusPages) {
status(HttpStatusCode.NotFound) { call, status ->
      val message = LocalFileContent(File("./kobweb_site/404.html"))
      call.respond(status, message)
   }
}

Which will respond successfully with this page if the JS file is not loaded, however, while executing the JS file, it causes a 404 while attempting to send an HTTP request in this line: https://github.com/varabyte/kobweb/blob/main/frontend/kobweb-core/src/jsMain/kotlin/com/varabyte/kobweb/navigation/Router.kt#L409

Reproduce steps

Consider downloading the minimal sample to save time. Run ./gradlew run and navigate to any page that doesn't exist.

OR:

  1. Create a new Kobweb project with a 404 page in pages and export the Kobweb as static layout kobweb export --layout static -p site.
  2. Create a new Ktor server project with StatusPages and Routing` plugins.
  3. Move the site/.kobweb/site to the current working directory of the Ktor server root project with the directory name kobweb_site.
  4. Setup the Ktor server to respond with the 404.html file in case of 404 status:
fun Application.module() {
    val kobwebSiteDirectory = Path("kobweb_site")

    routing {
        staticFiles("/", kobwebSiteDirectory.toFile()) {
            extensions("html")
        }
    }
    install(StatusPages) {
        status(HttpStatusCode.NotFound) { call, _ ->
            // This is identical to call.respondFile() but with 404 status.
            val message = LocalFileContent(kobwebSiteDirectory.resolve("404.html").toFile())
            call.respond(HttpStatusCode.NotFound, message)
        }
    }
}
  1. Navigate to any route that doesn't exist.
  2. The 404.html page is displayed correctly for a very short time but as the JS code executes, you will get 404 as the site router trying to navigate to a new route. This is the related line: https://github.com/varabyte/kobweb/blob/main/frontend/kobweb-core/src/jsMain/kotlin/com/varabyte/kobweb/navigation/Router.kt#L409).

You could also try to rename the JS file so the 404.html can't load it: mv temp.js invalid_temp.js. Now navigate to any route that doesn't exist and the page is displayed correctly but site functionality is broken. This confirms the issue is related to the JS code.

Workaround

A workaround is to redirect to 404:

status(HttpStatusCode.NotFound) { call, _ ->
  // Using 404.html instead of 404 also works as expected if the extensions are configured correctly.
  call.respondRedirect("/404")
}

Important

For this workaround to work correctly, the staticFiles block must be configured to use extensions with html instead of setting the default to index.html

staticFiles("/", kobwebSiteDirectory.toFile()) {
-  default("index.html")
+  extensions("html")
}

Using default("index.html") instead of extensions("html") will load the HTML version of the page without the JS script loaded causing site functionality to be broken.

Warning

Using both default("index.html") and extensions("html") will cause the server to always return index.html in case the page is not found which is not expected, so the default should not be set.

According to my testing, adding html to extensions should be always used instead of setting the default to index.html, at least when hosting a Kobweb static site.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions