我想在Kotlin脚本中使用Java Web套接字API接收HTTP请求。
我在请求中只需要两行,因此我尝试将整个请求作为String行来进行处理,对其进行迭代,并为这两行中的每行获取与regex匹配的行。
我使用文本文件的FileInputStream进行了测试,而不是从客户端发送的实际InputStream进行了测试。我只能迭代一次,所以无法获得第二行。我收到以下结果。
GET /hello.html HTTP / 1.1
线程“主”中的异常java.util.NoSuchElementException:序列不包含与谓词匹配的元素。 在RequestParam $ filterLines $ 1.invoke(RequestParam.kt:29) 在RequestParam $ filterLines $ 1.invoke(RequestParam.kt:6) 在RequestParam。(RequestParam.kt:19) 在RequestParamKt.main(RequestParam.kt:26)
官方Kotlin参考文献指出,用asSequence()实例化的Sequence不能重复多次。因此,我使用了Supplier接口,但这不起作用。
我之前尝试过相同的方法,但它确实起作用。我现在正在重写代码,因为以前的版本有点混乱。以前的版本是here
下面是我正在努力的当前版本。
import java.io.FileInputStream
import java.io.InputStream
import java.util.function.Supplier
import kotlin.streams.asSequence
class RequestParam(private val inputStream: InputStream) {
val path: String
val host: String
init {
//I'd like to receive request from client as multiple lines of String.
//I generated Supplier since instance made by asSequence() cannot be iterated more than once https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/index.html
val linesSupplier: Supplier<Sequence<String>> = Supplier { inputStream.bufferedReader().lines().asSequence() }
//I only need lines starting with "GET" or "Host:"
val regex = { x: String -> { y: String -> y.matches(Regex(x)) } }
val regexGet = regex("GET.*")
val regexHost = regex("Host:.*")
//Iterate supplier and get the first line that matches each regex
val filterLines = { x: Sequence<String>, y: (String) -> Boolean -> x.first(y) }
path = filterLines(linesSupplier.get(), regexGet)
println(path) //works fine
host = filterLines(linesSupplier.get(), regexHost)
println(host) // no good
}
}
fun main(args: Array<String>) {
//Test with some file
val inputStream = FileInputStream("C:\\path\\to\\my\\test.txt")
val requestParam = RequestParam(inputStream)
}
以及我在测试中使用的文本文件
GET /hello.html HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE5.01; Windows NT)
Host: www.barfoo.com
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
为什么我不能多次迭代linesSupplier?
答案 0 :(得分:2)
表示延迟评估的集合的序列类型。顶层 实例化序列的函数和扩展函数 序列。
对于没有解决方案的解决方案:如文档所述,序列应尝试懒惰地评估inputStream的“ lines”方法返回的流中的值。因此,对于第一个调用,它将读取流,而第二个调用将尝试执行相同的操作,这将失败,因为您无法两次读取该流。您可以使用toList而不是asSequence解决它。列表将读取一次并将其保存在内存中。如果您的内存不受限,它将解决您的问题。
val linesSupplier: List<String> = inputStream.bufferedReader().lines().toList()
编辑: 对于与供应商的解决方案:您应该能够通过将文件流的创建移至供应商来使其工作。在您的代码段中,供应商失败,因为您使用的是已经消耗的相同流。
val linesSupplier: Supplier<Sequence<String>> = Supplier { FileInputStream("C:\\test.txt").bufferedReader().lines().asSequence() }
答案 1 :(得分:0)
因为在第一次调用linesSupplier.get()
时消耗了inputStream
,而在第二次调用时它引发了异常。不用使用供应商,只需定义一个普通的Sequence
并使用它即可:
val lines: Sequence<String> = inputStream.bufferedReader().lines().asSequence()
//...
path = filterLines(lines, regexGet)
//...
host = filterLines(lines, regexHost)