2014-11-01 1 views
3

Я пытаюсь понять Middleware, написав очень простой менеджер сеансов.В Haskell WAI, как добавить заголовки в качестве промежуточного ПО?

Мне нужно добавить заголовок SetCookie в ответе. Я просмотрел пакет wai-extra и нашел wai-session.

Я использую wai-3.0.2, который, кажется, не дает мне прямого доступа к конструкторам типа Response, и все примеры, которые я нашел, соответствуют шаблону Response(..), чтобы добавить заголовки.

Можете ли вы указать мне правильное направление?

+1

Вы можете, конечно, импортировать 'Network.Wai.Internal' для соответствия шаблону конструкторам' Response'. – ibotty

+0

@ibotty Хорошо, я чувствую себя глупо. Я пробовал это, но это провалилось. Оказывается, это не сработало, потому что имя одного из конструкторов типа изменилось, и я не заметил. – rob

+0

в следующий раз попробуйте исследовать его в ghci. используйте ': i', и вы узнаете все конструкторы и где они определены. – ibotty

ответ

5

Редактировать: Версия 3.0.3.0 от Wai вводит вспомогательную функцию mapResponseHeaders, то же самое, что и mapHeader в примере ниже. Это означает, что пример больше не нужен для сопоставления рисунков на Response.

import Network.HTTP.Types (ResponseHeaders, Header) 
import Network.Wai (Middleware, Response, mapResponseHeaders) 

withHeader :: Header -> Middleware 
withHeader h app req respond = app req $ respond . addHeader h 

addHeader :: Header -> Response -> Response 
addHeader h = mapResponseHeaders (\hs -> h:hs) 

У меня есть что-то работает, и думаю, я понимаю, но будет действительно как отзывы и предложения. Я новичок в Haskell, и это мое первое использование Вай. Мой самый большой камень преткновения не понимал, что тип приложения изменился в Wai 3.0.0 на стиль продолжения прохождения. (Состояния документации это очень ясно, я просто пропустил первые 15 раз я читал.)

import Network.HTTP.Types (ResponseHeaders, Header) 
import Network.Wai (Middleware) 
import Network.Wai.Internal (Response(..)) 

withHeader :: Header -> Middleware 
withHeader h app req respond = app req $ respond . addHeader h 

mapHeader :: (ResponseHeaders -> ResponseHeaders) -> Response -> Response 
mapHeader f (ResponseFile s h b1 b2) = ResponseFile s (f h) b1 b2 
mapHeader f (ResponseBuilder s h b) = ResponseBuilder s (f h) b 
mapHeader f (ResponseStream s h b) = ResponseStream s (f h) b 
mapHeader _ [email protected](ResponseRaw _ _) = r 

addHeader :: Header -> Response -> Response 
addHeader h = mapHeader (\hs -> h:hs) 

Я не сделал никаких попыток изменить заголовки для ResponseRaw, потому что я не мог понять, каким образом.

Я не уверен, что достаточно ясно, что addHeader частично применяется и является функцией продолжения, передаваемой внутреннему приложению. Эта форма может быть более ясным (или уродливее):

withHeader h app req respond = app req $ \resp -> respond $ addHeader h resp 

Я скопировал mapHeader из wai-session, но добавили аргументы в пользу ResponseRaw.

+0

Очень жаль, что нужно импортировать конструкторы Response из Network.Wai.Internal, но, насколько я вижу, это единственный способ добиться этого. – hdgarrood

+0

Кроме того, для меня ясно, что приложение «addHeader» частично применяется. Я предпочел бы это, чем версия с расширенной версией. Наконец, в последнем шаблоне mapHeader я предпочел бы использовать '_' для' f', так как 'f' не используется. (Я думаю, что это вызвало бы предупреждение, если вы использовали -Wall?) – hdgarrood

+0

@hdgarrood Я изменил неиспользованный 'f' на' _'. Так лучше. Поскольку я больше привык к Haskell, я также предпочитаю частично примененную версию. Спасибо за комментарии! – rob

Смежные вопросы