Отправить запрос как тип содержимого x-www-form-urlencoded с 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
, Я вижу, что здесь есть несколько документов, но не ясно, как действовать дальше. Может быть, мне нужен экземпляр FormValue? Пример будет полезен.
1 ответ
Согласно вашему обсуждению с @Alexis, ваш клиент, похоже, отправляет JSON, в то время как сервер, как ожидается, будет urlencoded. Документация Post
показывает, как отправлять urlen-кодированные данные, используя :=
конструктор. В этом случае это будет
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