尝试使用 oAuth2 在 haskell 中执行 https get 请求
Trying to execute https get request in haskell with oAuth2
这是我尝试连接到 TDAmeritrade 的 api
使用 haskell 中的 Network.HTTP.Req 库接收 json 响应。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Lib
import Wuss
import Control.Concurrent
import Control.Monad
import Data.Text
import Network.WebSockets
import Network.Connection
import Network.WebSockets.Stream
import Data.Text.Lazy
import Data.ByteString
import Lens.Micro.GHC.Internal
import Network.Curl
import Data.ByteString.Lazy.UTF8
import Network.HTTP.Req
import Control.Monad
import Control.Monad.IO.Class
import Data.Aeson
import Data.Maybe
import Data.Monoid
import GHC.Generics
import Network.HTTP.Req
import Data.ByteString.Char8
tok = Data.ByteString.Char8.pack "accesstoken"
main :: IO ()
main = runReq defaultHttpConfig $ do
v <- req GET (https "api.tdameritrade.com" /: "v1" /: "userprincipals?fields=streamerConnectionInfo") (NoReqBody) jsonResponse (oAuth2Bearer tok)
liftIO $ Data.ByteString.Char8.putStrLn (responseBody v)
如果正确完成,响应应该只会给出一个错误,指出身份验证令牌不正确,因为我故意没有在这里提供有效的令牌。 “访问令牌”
如果我使用 bsResponse
而不是 jsonResponse
,它会进行类型检查,但不会使用 jsonResponse 进行类型检查。 TDAmeritrade 的回复将在 JSON.
中
这是错误:
No instance for (FromJSON Data.ByteString.Char8.ByteString)
arising from a use of ‘req’
这是我使用 bsResponse 的结果:
port = 443
secure = True
requestHeaders = [("Authorization","<REDACTED>")]
path = "/v1/userprincipals%3Ffields=streamerConnectionInfo"
queryString = ""
method = "GET"
proxy = Nothing
rawBody = False
redirectCount = 10
responseTimeout = ResponseTimeoutDefault
requestVersion = HTTP/1.1
}
(StatusCodeException (Response {responseStatus = Status {statusCode = 400, statusMessage = "Bad Request"}, responseVersion = HTTP/1.1, responseHeaders = [("Date","Wed, 08 Sep 2021 15:27:41 GMT"),("Content-Type","application/json"),("Content-Length","78"),("Connection","keep-alive"),("Host","api.tdameritrade.com"),("X-Forwarded-Port","9002"),("X-Forwarded-Proto","http"),("Accept-Encoding","gzip"),("Authorization","Bearer accesstoken"),("NS-Proxy-Client-IP","82.46.185.98"),("Access-Control-Allow-Origin",""),("Access-Control-Allow-Headers","origin, x-requested-with, accept, authorization, content-type, correlationid, apikey, application-name"),("Access-Control-Max-Age","3628800"),("Access-Control-Allow-Methods","GET, PUT, POST, DELETE, OPTIONS, HEAD, PATCH"),("X-Xss-Protection","1; mode=block"),("X-Content-Type-Options","nosniff"),("X-Frame-Options","SAMEORIGIN"),("Content-Security-Policy","frame-ancestors 'self'"),("Cache-Control","no-cache,no-store,must-revalidate"),("Strict-Transport-Security","max-age=31536000")], responseBody = (), responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}) "\n {\n \"error\":\"The endpoint doesnt exist.\"\n \t\t}\n "))
作为参考,终端中的这个 curl 命令产生了正确的响应:
curl -X GET --header "Authorization: Bearer authorizationtoken" "https://api.tdameritrade.com/v1/userprincipals?fields=streamerConnectionInfo"
我完全迷路了。请帮忙
要修复您的即时错误,您必须使用 (=:)
函数构造请求参数,而不是手动编写 ?fields=streamerConnectionInfo
部分。并且您还需要禁用错误状态代码检查。这是复制您的 curl
命令的工作代码:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Char8
import Network.HTTP.Req
import Control.Monad.IO.Class
import Data.Text
tok = Data.ByteString.Char8.pack "accesstoken"
main :: IO ()
main = runReq defaultHttpConfig { httpConfigCheckResponse = \_ _ _ -> Nothing } $ do
v <- req GET (https "api.tdameritrade.com" /: "v1" /: "userprincipals") (NoReqBody) bsResponse ("fields" =: ("streamerConnectionInfo" :: Text) <> oAuth2Bearer tok)
liftIO $ Data.ByteString.Char8.putStrLn (responseBody v)
另一个问题是从生成的 JSON 主体访问字段。我建议从阅读 the documentation of Aeson 开始,这是主要的 Haskell JSON 包。如果您使用 jsonResponse
请求类型,那么它会自动将响应转换为具有 FromJSON
实例的任何类型。
或许也能帮到你
这是我尝试连接到 TDAmeritrade 的 api 使用 haskell 中的 Network.HTTP.Req 库接收 json 响应。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Lib
import Wuss
import Control.Concurrent
import Control.Monad
import Data.Text
import Network.WebSockets
import Network.Connection
import Network.WebSockets.Stream
import Data.Text.Lazy
import Data.ByteString
import Lens.Micro.GHC.Internal
import Network.Curl
import Data.ByteString.Lazy.UTF8
import Network.HTTP.Req
import Control.Monad
import Control.Monad.IO.Class
import Data.Aeson
import Data.Maybe
import Data.Monoid
import GHC.Generics
import Network.HTTP.Req
import Data.ByteString.Char8
tok = Data.ByteString.Char8.pack "accesstoken"
main :: IO ()
main = runReq defaultHttpConfig $ do
v <- req GET (https "api.tdameritrade.com" /: "v1" /: "userprincipals?fields=streamerConnectionInfo") (NoReqBody) jsonResponse (oAuth2Bearer tok)
liftIO $ Data.ByteString.Char8.putStrLn (responseBody v)
如果正确完成,响应应该只会给出一个错误,指出身份验证令牌不正确,因为我故意没有在这里提供有效的令牌。 “访问令牌”
如果我使用 bsResponse
而不是 jsonResponse
,它会进行类型检查,但不会使用 jsonResponse 进行类型检查。 TDAmeritrade 的回复将在 JSON.
这是错误:
No instance for (FromJSON Data.ByteString.Char8.ByteString)
arising from a use of ‘req’
这是我使用 bsResponse 的结果:
port = 443
secure = True
requestHeaders = [("Authorization","<REDACTED>")]
path = "/v1/userprincipals%3Ffields=streamerConnectionInfo"
queryString = ""
method = "GET"
proxy = Nothing
rawBody = False
redirectCount = 10
responseTimeout = ResponseTimeoutDefault
requestVersion = HTTP/1.1
}
(StatusCodeException (Response {responseStatus = Status {statusCode = 400, statusMessage = "Bad Request"}, responseVersion = HTTP/1.1, responseHeaders = [("Date","Wed, 08 Sep 2021 15:27:41 GMT"),("Content-Type","application/json"),("Content-Length","78"),("Connection","keep-alive"),("Host","api.tdameritrade.com"),("X-Forwarded-Port","9002"),("X-Forwarded-Proto","http"),("Accept-Encoding","gzip"),("Authorization","Bearer accesstoken"),("NS-Proxy-Client-IP","82.46.185.98"),("Access-Control-Allow-Origin",""),("Access-Control-Allow-Headers","origin, x-requested-with, accept, authorization, content-type, correlationid, apikey, application-name"),("Access-Control-Max-Age","3628800"),("Access-Control-Allow-Methods","GET, PUT, POST, DELETE, OPTIONS, HEAD, PATCH"),("X-Xss-Protection","1; mode=block"),("X-Content-Type-Options","nosniff"),("X-Frame-Options","SAMEORIGIN"),("Content-Security-Policy","frame-ancestors 'self'"),("Cache-Control","no-cache,no-store,must-revalidate"),("Strict-Transport-Security","max-age=31536000")], responseBody = (), responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}) "\n {\n \"error\":\"The endpoint doesnt exist.\"\n \t\t}\n "))
作为参考,终端中的这个 curl 命令产生了正确的响应:
curl -X GET --header "Authorization: Bearer authorizationtoken" "https://api.tdameritrade.com/v1/userprincipals?fields=streamerConnectionInfo"
我完全迷路了。请帮忙
要修复您的即时错误,您必须使用 (=:)
函数构造请求参数,而不是手动编写 ?fields=streamerConnectionInfo
部分。并且您还需要禁用错误状态代码检查。这是复制您的 curl
命令的工作代码:
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Char8
import Network.HTTP.Req
import Control.Monad.IO.Class
import Data.Text
tok = Data.ByteString.Char8.pack "accesstoken"
main :: IO ()
main = runReq defaultHttpConfig { httpConfigCheckResponse = \_ _ _ -> Nothing } $ do
v <- req GET (https "api.tdameritrade.com" /: "v1" /: "userprincipals") (NoReqBody) bsResponse ("fields" =: ("streamerConnectionInfo" :: Text) <> oAuth2Bearer tok)
liftIO $ Data.ByteString.Char8.putStrLn (responseBody v)
另一个问题是从生成的 JSON 主体访问字段。我建议从阅读 the documentation of Aeson 开始,这是主要的 Haskell JSON 包。如果您使用 jsonResponse
请求类型,那么它会自动将响应转换为具有 FromJSON
实例的任何类型。
或许