Отправить запрос как тип содержимого 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
Другие вопросы по тегам