Вопрос обратного прокси на Haskell - PullRequest
0 голосов
/ 30 апреля 2018

Я новичок в Haskell и функциональном программировании. Чтобы получить практический опыт, я написал это простое приложение обратного прокси. Идея проста: на основе заголовка x-tenant-id в запросе прокси-сервер перенаправляет запрос соответствующему вышестоящему хосту tenant-${tenantid}. Приложение хорошо работает для запросов GET и DELETE. Но для POST и PUT время от времени (почти на каждый другой запрос) он жалуется на неправильный Content-Length, хотя в этом нет ничего плохого. Я выполнил поиск в Интернете, кажется, никто не сталкивался с подобной проблемой раньше, так что, вероятно, мой код где-то испортился.

Сообщение об ошибке:

WrongRequestBodyStreamSize 200 0

200 - фактическая длина контента, но сервер обратного потока считает, что это 0. Сначала я подумал, что запрос каким-то образом был усечен, но Wireshark обнаружил, что запрос был полностью отправлен исходящему потоку ... Теперь я предполагаю, что весь запрос разбит через прокси заголовки разделяются на два, заголовки находятся в первом запросе, а полезные данные попадают во второй.

Код:

{-# 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
...