我是 Haskell 和函数式编程的新手。为了获得一些实践经验,我编写了这个简单的反向代理应用程序。这个想法很简单,基于 x-tenant-id
请求中的header,代理将请求转发到对应的上游主机tenant-${tenantid}
.
该应用程序适用于 GET 和 DELETE 请求。但是对于 POST 和 PUT,它不时(几乎所有其他请求)都会提示不正确 Content-Length
,即使它没有任何问题。我在网上搜索了一下,好像以前没有人遇到过类似的问题,所以可能是我的代码在某处搞砸了。
错误信息:
WrongRequestBodyStreamSize 200 0
200 是实际的内容长度,但上游服务器认为它是 0。我的第一个想法是请求以某种方式被截断,但 Wireshark 透露请求已完全发送到上游......现在我的猜测是整个请求被分成两部分代理, header 位于第一个请求中,而有效负载则位于第二个请求中。
代码:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
module Main where
import qualified Network.HTTP.Client as Client
import qualified Network.HTTP.ReverseProxy as ReverseProxy
import qualified Network.Wai as Wai
import qualified Network.Wai.Request as Request
import qualified Network.Wai.Handler.Warp as Warp
import qualified Data.Maybe as Maybe
import qualified Data.ByteString as ByteString
main = do
manager <- Client.newManager $ Client.defaultManagerSettings { Client.managerConnCount = 5000, Client.managerIdleConnectionCount = 5000 }
let settings = Warp.setPort 80 $ Warp.setHTTP2Disabled Warp.defaultSettings
Warp.runSettings settings $ mainApp manager
mainApp :: Client.Manager -> Wai.Application
mainApp manager req res = do
let maybeUpstream = lookup "x-tenant-id" $ Wai.requestHeaders $ req
let upstream = if Maybe.isNothing(maybeUpstream) then "12345" else Maybe.fromJust(maybeUpstream)
proxyApp upstream manager req res
proxyApp :: ByteString.ByteString -> Client.Manager -> Wai.Application
proxyApp upstream manager req res = do
let host = ByteString.concat(["tenant-", upstream])
let dest = ReverseProxy.WPRProxyDest ReverseProxy.ProxyDest { ReverseProxy.pdHost = host, ReverseProxy.pdPort = 80 }
ReverseProxy.waiProxyTo (const $ return dest) ReverseProxy.defaultOnExc manager req res
最佳答案
我遇到了同样的问题,并针对 http-reverse-proxy
打开了 PR。修复它:https://github.com/fpco/http-reverse-proxy/pull/35 .
该解决方案在编写时有轻微的性能损失,但它有效。希望这将在审查中得到纠正。
关于Haskell 反向代理问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50103208/