1

所以,我有一个简单的 Id 类型:

newtype Id = Id String
    deriving (Show, Eq, Ord, Generic)

instance ToJSON Id
instance FromJSON Id
instance FromHttpApiData Id where parseUrlPiece = Right . Id . Text.unpack

一个仆人路线定义如下:

type SetEntryOrder = "entries" :> "order" :> ReqBody '[JSON] [Id] :> Post '[JSON] [Id]

我使用以下标头和请求正文向它发出请求:

POST /entries/order HTTP/1.1
Host: localhost:9090
Connection: keep-alive
Content-Length: 199
Pragma: no-cache
Cache-Control: no-cache
Origin: http://localhost:9090
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Content-Type: application/json
Accept: */*
Referer: http://localhost:9090/
Accept-Encoding: gzip, deflate
Accept-Language: en

["0pAWSlIHH38sApt0n101X2brrCkyYp","1aaaaaaaaaaaaaaaaaaaaaaaaaaaaa","2aaaaaaaaaaaaaaaaaaaaaaaaaaaaa","7T84N81O7T84N81O7T84N81Obeu4JU","vMfOGs2LvMfOGs2LvMfOGs2LzjlQIP","j1Ew8Ju7HzAIv2yH9ohcdl9Wm2o7qx"]

但是我得到了一个 400 并带有以下正文(根本没有输入路线):

Error in $: expected record (:*:), encountered Array

我克隆了 githubservant repo 并搜索了它的各个部分,但一无所获。

值得注意的是,我还有很多其他路线都可以正常工作。

我想也许我的Id类型没有被正确解码(Aeson 预期的记录或其他东西),但我可以在 GHCI 中毫无问题地使用仆人在引擎盖下所做的同样的事情:

> import Servant.API.ContentTypes (eitherDecodeLenient)
> eitherDecodeLenient "[\"hello\",\"hi\"]" :: Either String [Id]
Right [Id "hello",Id "hi"]

像这样为我的 Id 类型定义自定义 JSON 处理程序也无济于事:

instance ToJSON Id where
    toJSON (Id s) = String $ Text.pack s
instance FromJSON Id where
    parseJSON (String s) = return $ Id $ Text.unpack s
    parseJSON _ = empty

Sooo,有没有人知道为什么 Servant 在试图解码我的 Id 数组并扔给我 400 而不是进入我的路线时卡住了?:)

版本

堆栈 LTS 6.15,这意味着:

GHC 7.10.3、servant 0.7.1、servant-server 0.7.1、aeson 0.11.2.1

(我也测试了servant-0.8.1但没有变化)

原始代码

https://github.com/jsdw/talklicker/tree/master/server(路由定义见Routes.hs,Id定义见Types.hs)

更新!

所以,问题似乎是仆人匹配了错误的路线,因为通过将正确的数据传递给我的/entries/orders路线(事实上,我似乎可以用任何字符串替换“订单”,并且尾部斜杠没有区别!),我实际上可以到达我的/entries路线。将另一个路由片段(例如:> "dadada")添加到 SetEntryOrder 并使用它可以让我定位正确的路由。

有问题的重叠路线是:

type SetEntryOrder = HasSession :> "order" :> ReqBody '[JSON] [Id] :> Post '[JSON] [Id]

type AddEntry = HasSession :> ReqBody '[JSON] AddEntryInput :> Post '[JSON] Entry

请注意,这两个都在我的 Routes.hs 文件顶部以“条目”为前缀。我还没有弄清楚为什么会这样,但这是一个开始!

更新2!

问题解决了!实际上是因为我的路线重叠,所以我的错!我为自己做了很多事情,因为重叠的路线几乎接受了任何输入(但我忘记了这一点!)。交换周围的路线固定它。

4

0 回答 0