Haskell中GET请求的编码问题

时间:2019-08-01 17:10:52

标签: http haskell get jira

我正在尝试使用Haskell从Jira服务器获取一些Json数据。我将其视为“我在Haskell中遇到问题”,而不是编码或Jira,因为我的问题是在Haskell中进行此操作时。

URL(或查询)带有加号时,会发生此问题。建立我对theproject+order+by+created的请求后,Haskell将其打印为:

Request {
  host                 = "myjiraserver.com"
  port                 = 443
  secure               = True
  requestHeaders       = [("Content-Type","application/json"),("Authorization","<REDACTED>")]
  path                 = "/jira/rest/api/2/search"
  queryString          = "?jql=project%3Dtheproject%2Border%2Bby%2Bcreated"
  method               = "GET"
  proxy                = Nothing
  rawBody              = False
  redirectCount        = 10
  responseTimeout      = ResponseTimeoutDefault
  requestVersion       = HTTP/1.1
}

但是请求失败并显示以下响应:

- 'Error in the JQL Query: The character ''+'' is a reserved JQL character. You must
  enclose it in a string or use the escape ''\u002b'' instead. (line 1, character
  21)'

所以Jira似乎不喜欢Haskell的%2B。您对我可以如何解决此问题有任何建议,或者是否有任何有用的资源?在+order+by+created部分成功的情况下,相同的请求成功。

代码(从these examples修补):

{-# LANGUAGE OverloadedStrings #-}
import           Data.Aeson
import qualified Data.ByteString.Char8 as S8
import qualified Data.Yaml             as Yaml
import           Network.HTTP.Simple
import           System.Environment    (getArgs)

-- auth' is echo -e "username:passwd" | base64
foo urlBase proj' auth' = do
    let proj = S8.pack (proj' ++ "+order+by+created")
        auth = S8.pack auth'
    request'' <- parseRequest urlBase
    let request'
            = setRequestMethod "GET"
            $ setRequestPath "/jira/rest/api/2/search"
            $ setRequestHeader "Content-Type" ["application/json"]
            $ request''
        request
            = setRequestQueryString [("jql", Just (S8.append "project=" proj))]
            $ setRequestHeader "Authorization" [S8.append "Basic " auth]
            $ request'
    return request

main :: IO ()
main = do
    args <- getArgs
    case args of
      (urlBase:proj:auth:_) -> do
          request <- foo urlBase proj auth
          putStrLn $ show request
          response <- httpJSON request
          S8.putStrLn $ Yaml.encode (getResponseBody response :: Value) -- apparently this is required
          putStrLn ""

      _ -> putStrLn "usage..."

((如果您知道执行上述操作的更简单方法,那么我也会提出这样的建议,我只是想做一些与此Python类似的事情:

import requests
import sys
if len(sys.argv) >= 4:
    urlBase = sys.argv[1]
    proj = sys.argv[2]
    auth = sys.argv[3]
    urlBase += "/jira/rest/api/2/search?jql=project="
    proj += "+order+by+created"
    h = {}
    h["content-type"] = "application/json"
    h["authorization"] = "Basic " + auth
    r = requests.get(urlBase + proj, headers=h)
    print(r.json())

1 个答案:

答案 0 :(得分:3)

project+order+by+created是实际请求project order by created的{​​{3}}字符串(用空格代替+)。函数setRequestQueryString要求一个原始请求(带空格,未经URL编码),并对其进行URL编码。

您提供的用于比较的Python脚本实质上是手动进行URL编码。

因此解决方法是将原始请求放入proj

foo urlBase proj' auth' = do
    let proj = S8.pack (proj' ++ " order by created")  -- spaces instead of +
    ...