F# 尝试将 HTTP 响应写入 TCP 流

F# Trying to write HTTP response to TCP stream

我正在尝试用 F# 制作一个简单的 HTTP 服务器。但不幸的是,我停留在响应阶段,我正在尝试创建一个简单的 404 响应,但我的浏览器无法获取它,它只会加载和加载页面,永远不会去任何地方。我不知道我的代码哪里有问题。

let responseString = "HTTP/1.1 404 NOT FOUND";
let buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

let processRequest (client: TcpClient)  = 
    async {  do printfn "Incoming HTTP request..."
             use stream = client.GetStream()
             use sr = new StreamReader(stream)
             let! content = sr.ReadToEndAsync() |> Async.AwaitTask
             do 
                printfn "Stream contains:\n%s" content 
                stream.Write(buffer, 0, buffer.Length) 
                stream.Flush() }

let ip = IPAddress.Parse("127.0.0.1")
let listener = TcpListener(ip, 8080)
let startServer = 
    async { do listener.Start() 
            do printfn "Starting server..."
            while true do 
                let! context = listener.AcceptTcpClientAsync() |> Async.AwaitTask
                do! processRequest context }

Async.Start startServer

问题是,TCP 流不知道客户端何时发送了所有数据(除非您关闭浏览器),因此 StreamReader 永远被阻塞。 如果你想自己实现 HTTP,你需要(对于初学者)逐行读取并检查是否允许客户端发送更多数据。

正如@CaringDev 指出的那样,ReadToEnd 不会终止。也就是说,对于一个简单的 HTTP 服务器,您只需要阅读请求的第一行。这是您的代码的更新版本,它只读取第一行并以 200 OK 响应:

open System.Net

let processRequest (client: Sockets.TcpClient) = async {  
  printfn "Incoming HTTP request..."
  use stream = client.GetStream()
  use sr = new System.IO.StreamReader(stream)
  let line = sr.ReadLine()
  printfn "Request: %s" line
  let sw = new System.IO.StreamWriter(stream)
  sw.WriteLine("HTTP/1.1 200 OK\r\n\r\nHello World")
  sw.Flush()     
  }

let ip = IPAddress.Parse("127.0.0.1")
let listener = Sockets.TcpListener(ip, 8080)
let startServer = async { 
  do listener.Start() 
  do printfn "Starting server..."
  while true do 
    let! context = listener.AcceptTcpClientAsync() |> Async.AwaitTask
    processRequest context |> Async.Start
  }

Async.Start startServer

我也很想将 do! processRequest context 更改为 processRequest context |> Async.Start 以便您可以同时处理多个请求。