我发现了一个不安全的ktor-websocket服务器(ws://…(的文档:
https://ktor.io/docs/creating-web-socket-chat.html#creating-聊天客户端
我找到了一个安全的ktor http服务器的文档(https://...)
https://github.com/ktorio/ktor-documentation/tree/main/codeSnippets/snippets/ssl-embedded-server
但我似乎找不到或不知道如何为一个安全的ktor websocket服务器提供服务(wss://...)
我宁愿不在它前面使用像nginx这样的SSL反向代理
编辑:这里的代码:
import io.ktor.application.*
import io.ktor.http.cio.websocket.*
import io.ktor.network.tls.certificates.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.websocket.*
import java.io.*
fun main() {
val keyStoreFile = File("build/keystore.jks")
val keystore = generateCertificate(
file = keyStoreFile,
keyAlias = "sampleAlias",
keyPassword = "foobar",
jksPassword = "foobar"
)
val environment = applicationEngineEnvironment {
sslConnector(
keyStore = keystore,
keyAlias = "sampleAlias",
keyStorePassword = { "foobar".toCharArray() },
privateKeyPassword = { "foobar".toCharArray() }) {
port = 8443
keyStorePath = keyStoreFile
}
module(Application::module)
}
embeddedServer(Netty, environment).start(wait = true)
}
private fun Application.module() {
install(WebSockets)
routing {
get("/") { // works at https://localhost:8443 in Firefox after approving cert
call.respondText("This is https")
}
webSocket("/chat") { // fails at wss://localhost:8443/chat in Websocket js client with "Firefox can’t establish a connection to the server"
send("This is wss")
}
}
}
问题是使用自签名证书。我尝试了Chrome,并将其设置为接受localhost上的自签名证书,这是有效的。Firebox提供的错误消息表明无法建立连接,而实际上它拒绝了证书。
事实上,使用ktor的安全websocket服务器确实可以像@AleksiTierman建议的那样工作。它的配置方式与https服务器相同。
我已经用poster测试过了,效果很好
您不能在浏览器中使用ws://或wss://协议,而是使用poster或其他websocket客户端。
Application.kt:
import com.example.plugins.configureRouting
import com.example.plugins.configureSerialization
import com.example.plugins.configureSockets
import io.ktor.network.tls.certificates.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import org.slf4j.LoggerFactory
import java.io.File
fun main() {
val keyStoreFile = File("build/keystore.jks")
val keystore = generateCertificate(
file = keyStoreFile,
keyAlias = "sampleAlias",
keyPassword = "foobar",
jksPassword = "foobar"
)
val environment = applicationEngineEnvironment {
log = LoggerFactory.getLogger("ktor.application")
// no ssl, ws://127.0.0.1:6751
connector {
host = "127.0.0.1"
port = 6751
}
// with ssl, wss://127.0.0.1:6752
sslConnector(
keyStore = keystore,
keyAlias = "sampleAlias",
keyStorePassword = { "foobar".toCharArray() },
privateKeyPassword = { "foobar".toCharArray() }) {
keyStorePath = keyStoreFile
host = "127.0.0.1"
port = 6752
}
this.module {
configureSockets()
configureRouting()
}
}
embeddedServer(Netty, environment).start(wait = true)
/*
embeddedServer(Netty, port = 6752, host = "127.0.0.1") {
configureSockets()
configureRouting()
}.start(wait = true)
*/
}
Sockets.kt:
import io.ktor.serialization.kotlinx.*
import io.ktor.server.application.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import kotlinx.coroutines.channels.ClosedReceiveChannelException
import kotlinx.serialization.json.Json
import java.time.Duration
fun Application.configureSockets() {
routing {
this@configureSockets.install(WebSockets) {
contentConverter = KotlinxWebsocketSerializationConverter(Json)
pingPeriod = Duration.ofSeconds(3)
timeout = Duration.ofSeconds(5)
maxFrameSize = Long.MAX_VALUE
masking = false
}
webSocket("/echo") {
println("onConnect")
try {
for (frame in incoming) {
val text = (frame as Frame.Text).readText()
println("onMessage")
send(Frame.Text(text))
}
} catch (e: ClosedReceiveChannelException) {
e.printStackTrace()
println("onClose ${closeReason.await()}")
} catch (e: Throwable) {
e.printStackTrace()
println("onError ${closeReason.await()}")
}
}
}
}