7、Ktor學習-配置伺服器;

Melrose發表於2019-03-05

  Ktor在外部配置檔案中使用HOCON(Human-Optimized Config Object Notation)格式。 在此檔案中,您可以配置要偵聽的埠或要載入的模組等內容。 此格式類似於JSON,但經過優化,可供人類讀取和編寫,並支援環境變數替換等其他功能。 在這種情況下,您將伺服器引擎配置為與指向特定EngineMain的mainClassName一起使用。

  當使用embeddedServer時,Ktor還使用一組帶有型別DSL(域特定語言)的lambda來配置應用程式和伺服器引擎。

HOCON檔案


  這是配置Ktor應用程式的首選方法,因為它允許您輕鬆更改配置,而無需重新編譯應用程式。

  當Ktor使用EngineMain啟動時,或者通過呼叫commandLineEnvironment,它會嘗試從應用程式資源載入名為application.conf的HOCON檔案。 您可以使用命令列引數更改檔案的位置。

可用作mainClassName的可用開發引擎:

  io.ktor.server.cio.EngineMain
  io.ktor.server.tomcat.EngineMain
  io.ktor.server.jetty.EngineMain
  io.ktor.server.netty.EngineMain
複製程式碼

  Ktor僅要求您使用ktor.application.modules屬性指定在啟動伺服器時要載入的模組。 所有其他屬性都是可選的。

  Ktor(application.conf)的典型簡單HOCON檔案如下所示:

ktor {
    deployment {
        port = 8080
    }

    application {
        modules = [ io.ktor.samples.metrics.MetricsApplicationKt.main ]
    }
}
複製程式碼

  使用.表示法相當於:

ktor.deployment.port = 8080
ktor.application.modules = [ io.ktor.samples.metrics.MetricsApplicationKt.main ]
複製程式碼

  Ktor允許您進行更多配置:從其他核心配置到Ktor功能,甚至是應用程式的自定義配置:

ktor {
    deployment {
        environment = development
        port = 8080
        sslPort = 8443
        autoreload = true
        watch = [ httpbin ]
    }

    application {
        modules = [ io.ktor.samples.httpbin.HttpBinApplicationKt.main ]
    }

    security {
        ssl {
            keyStore = build/temporary.jks
            keyAlias = mykey
            keyStorePassword = changeit
            privateKeyPassword = changeit
        }
    }
}

jwt {
    domain = "https://jwt-provider-domain/"
    audience = "jwt-audience"
    realm = "ktor app"
}

youkube {
  session {
    cookie {
      key = 03e156f6058a13813816065
    }
  }
  upload {
    dir = ktor-samples/ktor-samples-youkube/.video
  }
}
複製程式碼

注:你可以安裝一個用於HOCON的IntelliJ外掛。

命令列


  使用commandLineEnvironment(任何EngineMain main)時,可以使用多個開關和配置引數來配置應用程式模組。

  如果從命令列使用-config = anotherfile.conf啟動應用程式,它將從特定的本地檔案而不是從資源載入配置檔案。

java -jar myapp-fatjar.jar -port=8080
複製程式碼

配置embeddedServer


   embeddedServer是啟動Ktor應用程式的簡單方法。 您提供自己的主要功能,並且更明確,更容易理解究竟發生了什麼。

  embeddedServer包含一個可選引數configure,允許您設定第一個引數中指定的引擎的配置。 獨立於所使用的引擎,您將擁有一些可配置的屬性:

embeddedServer(AnyEngine, configure = {
    // Size of the event group for accepting connections
    connectionGroupSize = parallelism / 2 + 1
    // Size of the event group for processing connections,
    // parsing messages and doing engine's internal work 
    workerGroupSize = parallelism / 2 + 1
    // Size of the event group for running application code 
    callGroupSize = parallelism 
}) {
    // ...
}.start(true)
複製程式碼

多個聯結器


  可以使用applicationEngineEnvironment通過程式碼定義幾個聯結器。

  在applicationEngineEnvironment中,您可以定義HTTP和HTTPS聯結器:

  定義一個HTTP聯結器:

connector {
    host = "0.0.0.0"
    port = 9090
}
複製程式碼

  定義一個HTTPS聯結器:

sslConnector(keyStore = keyStore, keyAlias = "mykey", keyStorePassword = { "changeit".toCharArray() }, privateKeyPassword = { "changeit".toCharArray() }) {
    port = 9091
    keyStorePath = keyStoreFile.absoluteFile
}
複製程式碼

  完整的例子:

fun main(args: Array<String>) {
    val env = applicationEngineEnvironment {
        module {
            main()
        }
        // Private API
        connector {
            host = "127.0.0.1"
            port = 9090
        }
        // Public API
        connector {
            host = "0.0.0.0"
            port = 8080
        }
    }
    embeddedServer(Netty, env).start(true)
}
複製程式碼

該應用程式將處理所有連線。 您可以訪問每個ApplicationCall的本地埠,因此您可以根據本地埠決定要執行的操作:

fun Application.main() {
    routing {
        get("/") {
            if (call.request.local.port == 8080) {
                call.respondText("Connected to public api")
            } else {
                call.respondText("Connected to private api")
            }
        }
    }
}
複製程式碼

Netty


使用Netty作為引擎時,除了常用屬性外,還可以配置其他一些屬性:

embeddedServer(Netty, configure = {
    // 儲存無法立即處理的[ApplicationCall]例項的佇列的大小
    requestQueueLimit = 16 
    shareWorkGroup = false 
    // 使用者提供的功能來配置Netty的[ServerBootstrap]
    configureBootstrap = {
        // ...
    } 
    // 向客戶端傳送響應的超時(以秒為單位)
    responseWriteTimeoutSeconds = 10 
}) {
    // ...
}.start(true)
複製程式碼

Jetty


使用Jetty作為引擎時,除了常用屬性外,還可以配置Jetty伺服器。

embeddedServer(Jetty, configure = {
    // 提供lambda的屬性,該lambda將在Jetty伺服器初始化期間以伺服器例項作為引數進行呼叫。
    configureServer = {
        // ...
    } 
}) {
    // ...
}.start(true)
複製程式碼

CIO


使用CIO(Coroutine I/O)作為引擎時,除了常用屬性外,還可以配置connectionIdleTimeoutSeconds屬性。

embeddedServer(CIO, configure = {
    // 伺服器將保持HTTP IDLE連線開啟的秒數。
    // 如果沒有活動請求正在執行,則連線是IDLE。
    connectionIdleTimeoutSeconds = 45
}) {
    // ...
}.start(true)
複製程式碼

Tomcat


使用Tomcat時,除了常用屬性外,還可以配置Tomcat伺服器。

embeddedServer(Tomcat, configure = {
    // 提供在將Tomcat伺服器初始化期間以伺服器例項作為引數呼叫的lambda的屬性。
    configureTomcat { // this: Tomcat ->
        // ...
    }
}) {
    // ...
}.start(true)
複製程式碼

可用的配置引數


有一個Ktor可以理解的屬性列表,您可以從命令列或HOCON檔案傳遞這些屬性。

引數 引數路徑 預設值 描述
jar JAR檔案的路徑
config 配置檔案的路徑(而不是資源中的application.conf)
host ktor.deployment.host 0.0.0.0 繫結主機
port ktor.deployment.port 80 繫結埠
watch ktor.deployment.watch [] 用於監視重新載入的程式包路徑
ktor.application.id Application 用於記錄的應用程式識別符號
ktor.deployment.callGroupSize parallelism 執行應用程式程式碼的事件組大小
ktor.deployment.callGroupSize parallelism 執行應用程式程式碼的事件組大小
ktor.deployment.connectionGroupSize parallelism / 2 + 1 事件組接受連線大小

從程式碼中讀取配置


如果您使用的是EngineMain而不是embeddedServer,則會載入HOCON檔案,您可以訪問其配置屬性。

您還可以定義任意屬性路徑以配置應用程式。

val port: String = application.environment.config
    .propertyOrNull("ktor.deployment.port")?.getString()
    ?: "80"
複製程式碼

使用環境變數


對於HOCON,如果要使用環境變數配置某些引數,可以使用${ENV}語法來使用環境替換。 例如:

ktor {
    deployment {
        port = ${PORT}
    }
}
複製程式碼

如果由於環境不存在而要為屬性提供預設值,可以使用預設值設定該屬性,然後使用$ {?ENV}語法再次設定該屬性:

ktor {
    deployment {
        port = 8080
        port = ${?PORT}
    }
}
複製程式碼

如果您使用的是embeddedServer,您仍然可以使用Java中的System.getenv。 例如:

val port = System.getenv("PORT")?.toInt() ?: 8080
複製程式碼

如何區分開發環境


您可能希望根據伺服器是在本地執行還是在生產伺服器上執行不同的操作。

HOCON & ENV

您可以使用application.conf檔案來設定將儲存環境的變數,然後在執行時檢查該變數並確定要執行的操作。 您可以將其配置為檢查環境變數KTOR_ENV並提供預設值dev。 然後在生產中設定KTOR_ENV = prod

ktor {
    environment = dev
    environment = ${?KTOR_ENV}
}
複製程式碼

您可以從應用程式訪問此配置,並使用一些擴充套件屬性來簡化操作:

fun Application.module() {
    when {
        isDev -> {
            // Do things only in dev   
        }
        isProd -> {
            // Do things only in prod
        }
    }
    // Do things for all the environments
}

val Application.envKind get() = environment.config.property("ktor.environment").getString()
val Application.isDev get() = envKind == "dev"
val Application.isProd get() = envKind != "dev"
複製程式碼

相關文章