问题描述
我想实现与Ktor和KMongo一个RESTful API。我连接的MongoDB阿特拉斯数据库和它工作得很好。
然后我准备部署在Heroku API的第一个版本,现在当我本地运行的每个查询的数据库抛出此异常:
2021-01-07 15:10:30.211 [eventLoopGroupProxy-4-2] INFO org.mongodb.driver.cluster - Cluster created with settings {hosts=[127.0.0.1:27017],srvHost=cluster0.euib1.mongodb.net,mode=MULTIPLE,requiredClusterType=REPLICA_SET,serverSelectionTimeout='30000 ms',maxWaitQueueSize=500,requiredreplicasetName='atlas-hl2rus-shard-0'}
15:10:30 web.1 | 2021-01-07 15:10:30.258 [cluster-ClusterId{value='5ff7165648f4085f7af773f9',description='null'}-srv-cluster0.euib1.mongodb.net] INFO org.mongodb.driver.cluster - Adding discovered server cluster0-shard-00-00.euib1.mongodb.net:27017 to client view of cluster
15:10:30 web.1 | 2021-01-07 15:10:30.268 [eventLoopGroupProxy-4-2] ERROR Application - Unhandled: GET - /books
15:10:30 web.1 | java.lang.NullPointerException: Cannot invoke "com.mongodb.connection.ClusterDescription.getConnectionMode()" because "clusterDescription" is null
15:10:30 web.1 | at com.mongodb.async.client.ClientSessionHelper.getServerDescriptionListToConsiderForSessionSupport(ClientSessionHelper.java:107)
15:10:30 web.1 | at com.mongodb.async.client.ClientSessionHelper.createClientSession(ClientSessionHelper.java:63)
15:10:30 web.1 | at com.mongodb.async.client.ClientSessionHelper.withClientSession(ClientSessionHelper.java:51)
15:10:30 web.1 | at com.mongodb.async.client.OperationExecutorImpl.execute(OperationExecutorImpl.java:66)
15:10:30 web.1 | at com.mongodb.async.client.MongoIterableImpl.batchCursor(MongoIterableImpl.java:161)
15:10:30 web.1 | at com.mongodb.async.client.MongoIterableSubscription.requestinitialData(MongoIterableSubscription.java:46)
15:10:30 web.1 | at com.mongodb.async.client.AbstractSubscription.tryRequestinitialData(AbstractSubscription.java:151)
15:10:30 web.1 | at com.mongodb.async.client.AbstractSubscription.request(AbstractSubscription.java:84)
15:10:30 web.1 | at com.mongodb.reactivestreams.client.internal.ObservabletoPublisher$1$1.request(ObservabletoPublisher.java:50)
15:10:30 web.1 | at kotlinx.coroutines.reactive.SubscriptionChannel.onReceiveEnqueued(Channel.kt:64)
15:10:30 web.1 | at kotlinx.coroutines.channels.AbstractChannel.enqueueReceive(AbstractChannel.kt:592)
15:10:30 web.1 | at kotlinx.coroutines.channels.AbstractChannel.access$enqueueReceive(AbstractChannel.kt:488)
15:10:30 web.1 | at kotlinx.coroutines.channels.AbstractChannel$Itr.hasNextSuspend(AbstractChannel.kt:841)
15:10:30 web.1 | at kotlinx.coroutines.channels.AbstractChannel$Itr.hasNext(AbstractChannel.kt:827)
15:10:30 web.1 | at org.litote.kmongo.coroutine.CoroutinePublisherKt.toList(CoroutinePublisher.kt:56)
15:10:30 web.1 | at org.litote.kmongo.coroutine.CoroutinePublisher.toList(CoroutinePublisher.kt:46)
15:10:30 web.1 | at com.flockware.BookControllerKt$booksRoutes$1$1.invokeSuspend(BookController.kt:29)
15:10:30 web.1 | at com.flockware.BookControllerKt$booksRoutes$1$1.invoke(BookController.kt)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1 | at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:102)
15:10:30 web.1 | at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
15:10:30 web.1 | at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)
15:10:30 web.1 | at kotlinx.coroutines.CoroutinescopeKt.coroutinescope(Coroutinescope.kt:189)
15:10:30 web.1 | at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:101)
15:10:30 web.1 | at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:142)
15:10:30 web.1 | at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1 | at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1 | at io.ktor.routing.Routing.executeResult(Routing.kt:151)
15:10:30 web.1 | at io.ktor.routing.Routing.interceptor(Routing.kt:35)
15:10:30 web.1 | at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:103)
15:10:30 web.1 | at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1 | at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:110)
15:10:30 web.1 | at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1 | at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1 | at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:118)
15:10:30 web.1 | at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:243)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:113)
15:10:30 web.1 | at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:133)
15:10:30 web.1 | at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
15:10:30 web.1 | at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:118)
15:10:30 web.1 | at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
15:10:30 web.1 | at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
15:10:30 web.1 | at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:182)
15:10:30 web.1 | at kotlinx.coroutines.BuildersKt.startCoroutineImpl(UnkNown Source)
15:10:30 web.1 | at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:145)
15:10:30 web.1 | at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:54)
15:10:30 web.1 | at kotlinx.coroutines.BuildersKt.launch(UnkNown Source)
15:10:30 web.1 | at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
15:10:30 web.1 | at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
15:10:30 web.1 | at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
15:10:30 web.1 | at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
15:10:30 web.1 | at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
15:10:30 web.1 | at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
15:10:30 web.1 | at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
15:10:30 web.1 | at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
15:10:30 web.1 | at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
15:10:30 web.1 | at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
15:10:30 web.1 | at io.ktor.server.netty.EventLoopGroupProxy$Companion$create$factory$1$1.run(NettyApplicationEngine.kt:216)
15:10:30 web.1 | at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
15:10:30 web.1 | at java.base/java.lang.Thread.run(Thread.java:832)
我对数据库的连接以这种方式:
KMongo.createClient("mongodb+srv://<username>:<password>@cluster0.euib1.mongodb.net/<dbname>?retryWrites=true&w=majority").coroutine
我的摇篮文件:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
}
}
apply plugin: 'kotlin'
apply plugin: 'application'
group 'com.example'
version '0.0.1'
mainClassName = 'com.example.ApplicationKt'
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
manifest {
attributes 'Main-Class': mainClassName
}
}
sourceSets {
main.kotlin.srcDirs = main.java.srcDirs = ['src']
test.kotlin.srcDirs = test.java.srcDirs = ['test']
main.resources.srcDirs = ['resources']
test.resources.srcDirs = ['testresources']
}
repositories {
mavenLocal()
jcenter()
maven { url 'https://kotlin.bintray.com/ktor' }
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "io.ktor:ktor-server-netty:$ktor_version"
implementation "ch.qos.logback:logback-classic:$logback_version"
implementation "io.ktor:ktor-server-core:$ktor_version"
implementation "io.ktor:ktor-server-host-common:$ktor_version"
implementation "io.ktor:ktor-jackson:$ktor_version"
implementation "io.ktor:ktor-locations:$ktor_version"
implementation "io.ktor:ktor-metrics:$ktor_version"
testImplementation "io.ktor:ktor-server-tests:$ktor_version"
implementation 'org.litote.kmongo:kmongo-coroutine:3.10.0'
implementation group: 'org.koin',name: 'koin-ktor',version: '2.0.0-beta-1'
implementation group: 'org.koin',name: 'koin-core-ext',version: '2.0.0-beta-1'
testImplementation group: 'org.koin',name: 'koin-test',version: '2.0.0-beta-1'
}
这是ApplicationKt.kt:
fun main(args: Array<String>) {
embeddedServer(Netty,commandLineEnvironment(args)).start(true)
}
@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(CORS) {
method(HttpMethod.Options)
method(HttpMethod.Post)
method(HttpMethod.Put)
method(HttpMethod.Delete)
method(HttpMethod.Patch)
header(HttpHeaders.Authorization)
header("MyCustomHeader")
allowCredentials = true
anyHost() // @Todo: Don't do this in production if possible. Try to limit it.
}
install(ContentNegotiation) {
jackson {
enable(SerializationFeature.INDENT_OUTPUT)
}
}
install(Locations) {}
installKoin {
modules(mongoModule)
}
routing {
booksRoutes()
install(StatusPages) {
exception<AuthenticationException> { cause ->
call.respond(HttpStatusCode.Unauthorized)
}
exception<AuthorizationException> { cause ->
call.respond(HttpStatusCode.Forbidden)
}
}
}
}
class AuthenticationException : RuntimeException()
class AuthorizationException : RuntimeException()
和这些路线:
fun Route.booksRoutes() {
val logger: Logger = LoggerFactory.getLogger("BooksController")
val client: CoroutineClient by inject()
route("/books") {
get("") {
val books = client.getDatabase(DB_NAME)
.getCollection<Book>(BOOKS_COLLECTION)
.find()
.toList()
call.respond(HttpStatusCode.OK,books)
}
post<Book>("") { request ->
logger.debug("$request")
client.getDatabase(DB_NAME)
.getCollection<Book>(BOOKS_COLLECTION)
.insertOne(request)
call.respond(HttpStatusCode.OK)
}
get("/{bookId}") {
val bookId:String = call.parameters["bookId"]!!
val book = client.getDatabase(DB_NAME)
.getCollection<Book>(BOOKS_COLLECTION)
.findOneById(bookId)
if (book == null)
call.respond(HttpStatusCode.NotFound)
else
call.respond(HttpStatusCode.OK,book)
}
}
}
这是我第一次使用 MongoDB,所以这可能是一个愚蠢的错误。但是,如果这个问题是在我的代码或MongoDB中阿特拉斯配置一个无法理解。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)