使用wreq将请求作为x-www-form-urlencoded的内容类型发送

时间:2017-05-13 18:00:41

标签: json haskell wreq

我本周末学会使用wreq而且我遇到了一些奇怪的行为。

我有一个模块AuthRequest

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
module AuthRequest where

import Data.Aeson
import GHC.Generics
import Data.Monoid

data AuthRequest = AuthRequest {
    client_id :: String
  , client_secret :: String
  , grant_type :: String
} deriving (Generic,  Show)

instance ToJSON AuthRequest where
    toJSON (AuthRequest id_ secret grant) =
      object [ "client_id" .= id_
             , "client_secret" .= secret
             , "grant_type" .= grant
             ]
    toEncoding(AuthRequest id_ secret grant) =
      pairs ("client_id" .= id_ <> "client_secret" .= secret <> "grant_type" .= grant)

和模块HttpDemo

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
module HttpDemo where

import Control.Lens
import Network.Wreq
import AuthRequest
import Data.Aeson

clientId = "some_id"
clientSecret = "some_secret"
url = "http://localhost:5000"

opts :: Options
opts = defaults
  & header "Content-Type" .~ ["application/x-www-form-urlencoded"]

req :: AuthRequest
req = AuthRequest clientId clientSecret "credentials"

postIt = postWith opts url (toJSON req)

另一方面,我有一个简单的python烧瓶服务器,它使用断点监听此请求,以便我可以看到通过的值。

当我查看服务器端的request.form时,我看到了这一点:ImmutableMultiDict([('{"client_secret":"some_secret","client_id":"some_id","grant_type":"whatever"}', '')])

关键是我的帖子应该是什么!

但是如果我使用请求python库提出类似的请求

requests.post('http://localhost:5000', data={'client_id': clientId, 'client_secret': clientSecret, 'grant_type': grant_type}, headers={'content-type': 'application/x-www-form-urlencoded'})

我明白了我的期望:ImmutableMultiDict([('grant_type', 'whatever'), ('client_id', 'some_id'), ('client_secret', 'some_secret')])

我认为我想要的是将此请求发送为x-www-form-urlencoded。我看到有一些文档here围绕着这个,但不清楚如何继续。也许我需要一个FormValue实例?一个例子会有所帮助。

1 个答案:

答案 0 :(得分:1)

根据您与@Alexis的讨论,您的客户端似乎正在发送JSON,而服务器预计是urlencoded。 Post的文档显示了如何使用:=构造函数发送urlencoded数据。在这种情况下,这将是

postIt = post url ["client_id" := clientId, "client_secret" := clientSecret, "grant_type" := grantType]

我使用post而不是postWith给出了示例,因为默认情况下它使用的是application/x-www-form-urlencoded

OverloadedStrings似乎有轻微的并发症。为了制作可编译的程序,我不得不删除AuthRequest模块并明确地给出常量类型如下

{-# LANGUAGE OverloadedStrings #-}
module Main where

import Network.Wreq
import Data.ByteString as B

clientId = "some_id" :: ByteString
clientSecret = "some_secret" :: ByteString
grantType = "credentials" :: ByteString
url = "http://localhost:8080"

postIt = post url ["client_id" := clientId, "client_secret" := clientSecret, "grant_type" := grantType]

main = postIt