Quick.HttpClient.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. { ***************************************************************************
  2. Copyright (c) 2016-2021 Kike Pérez
  3. Unit : Quick.HttpClient
  4. Description : Json Http Client
  5. Author : Kike Pérez
  6. Version : 1.1
  7. Created : 22/05/2018
  8. Modified : 02/08/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.HttpClient;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. Classes,
  26. SysUtils,
  27. Quick.Commons,
  28. {$IFDEF DELPHIXE8_UP}
  29. System.Net.HttpClient,
  30. System.Net.URLClient,
  31. System.NetConsts,
  32. System.JSON;
  33. {$ELSE}
  34. {$IFDEF DELPHIXE7_UP}
  35. System.JSON,
  36. {$ENDIF}
  37. IdHTTP,
  38. IdException,
  39. {$IFDEF FPC}
  40. fpjson;
  41. {$ELSE}
  42. Data.DBXJSON;
  43. {$ENDIF}
  44. {$ENDIF}
  45. type
  46. IHttpRequestResponse = interface
  47. ['{64DC58F7-B551-4619-85E9-D13E781529CD}']
  48. function StatusCode : Integer;
  49. function StatusText : string;
  50. function Response : TJSONObject;
  51. end;
  52. THttpRequestResponse = class(TInterfacedObject,IHttpRequestResponse)
  53. private
  54. fStatusCode : Integer;
  55. fStatusText : string;
  56. fResponse : TJSONObject;
  57. public
  58. {$IFDEF DELPHIXE8_UP}
  59. constructor Create(aResponse : IHTTPResponse; const aContent : string);
  60. {$ELSE}
  61. constructor Create(aResponse : TIdHTTPResponse; const aContent : string);
  62. {$ENDIF}
  63. destructor Destroy; override;
  64. function StatusCode : Integer;
  65. function StatusText : string;
  66. function Response : TJSONObject;
  67. end;
  68. TJsonHttpClient = class
  69. private
  70. {$IFDEF DELPHIXE8_UP}
  71. fHTTPClient : System.Net.HttpClient.THTTPClient;
  72. {$ELSE}
  73. fHTTPClient : TIdHTTP;
  74. {$ENDIF}
  75. fUserAgent : string;
  76. fContentType : string;
  77. fResponseTimeout : Integer;
  78. fConnectionTimeout : Integer;
  79. fHandleRedirects : Boolean;
  80. procedure SetContentType(const aValue: string);
  81. procedure SetUserAgent(const aValue: string);
  82. procedure SetResponseTimeout(const aValue: Integer);
  83. procedure SetConnectionTimeout(const aValue: Integer);
  84. procedure SetHandleRedirects(const aValue: Boolean);
  85. public
  86. constructor Create;
  87. destructor Destroy; override;
  88. property UserAgent : string read fUserAgent write SetUserAgent;
  89. property ContentType : string read fContentType write SetContentType;
  90. property ResponseTimeout : Integer read fResponseTimeout write SetResponseTimeout;
  91. property ConnectionTimeout : Integer read fConnectionTimeout write SetConnectionTimeout;
  92. property HandleRedirects : Boolean read fHandleRedirects write SetHandleRedirects;
  93. function Get(const aURL : string) : IHttpRequestResponse;
  94. function Post(const aURL, aInContent : string; aHeaders : TPairList = nil) : IHttpRequestResponse; overload;
  95. function Post(const aURL : string; aInContent : TStream) : IHttpRequestResponse; overload;
  96. function Post(const aURL : string; aJsonContent : TJsonObject) : IHttpRequestResponse; overload;
  97. function Put(const aURL, aInContent : string) : IHttpRequestResponse;
  98. end;
  99. implementation
  100. const
  101. DEF_USER_AGENT = 'XLHttpClient';
  102. constructor TJsonHttpClient.Create;
  103. begin
  104. {$IFDEF DELPHIXE8_UP}
  105. fHTTPClient := THTTPClient.Create;
  106. fHTTPClient.ContentType := 'application/json';
  107. fHTTPClient.UserAgent := DEF_USER_AGENT;
  108. {$ELSE}
  109. fHTTPClient := TIdHTTP.Create(nil);
  110. fHTTPClient.Request.ContentType := 'application/json';
  111. fHTTPClient.Request.UserAgent := DEF_USER_AGENT;
  112. {$ENDIF}
  113. end;
  114. destructor TJsonHttpClient.Destroy;
  115. begin
  116. fHTTPClient.Free;
  117. inherited;
  118. end;
  119. function TJsonHttpClient.Get(const aURL : string) : IHttpRequestResponse;
  120. var
  121. {$IFDEF DELPHIXE8_UP}
  122. resp : IHTTPResponse;
  123. {$ELSE}
  124. resp : TIdHTTPResponse;
  125. {$ENDIF}
  126. bodycontent : TStringStream;
  127. responsecontent : TStringStream;
  128. begin
  129. bodycontent := TStringStream.Create('',TEncoding.UTF8);
  130. try
  131. responsecontent := TStringStream.Create('',TEncoding.UTF8);
  132. try
  133. {$IFDEF DELPHIXE8_UP}
  134. resp := fHTTPClient.Get(aURL,responsecontent,nil);
  135. {$ELSE}
  136. {$If Defined(FPC) OR Not Defined(DELPHIXE8_UP)}
  137. fHTTPClient.Get(aURL,responsecontent);
  138. {$ELSE}
  139. fHTTPClient.Get(aURL,responsecontent,nil);
  140. {$ENDIF}
  141. resp := fHTTPClient.Response;
  142. {$ENDIF}
  143. Result := THttpRequestResponse.Create(resp,responsecontent.DataString);
  144. finally
  145. responsecontent.Free;
  146. end;
  147. finally
  148. bodycontent.Free;
  149. end;
  150. end;
  151. function TJsonHttpClient.Post(const aURL, aInContent : string; aHeaders : TPairList = nil) : IHttpRequestResponse;
  152. var
  153. pair : TPairItem;
  154. {$IFDEF DELPHIXE8_UP}
  155. resp : IHTTPResponse;
  156. headers : TArray<TNameValuePair>;
  157. {$ELSE}
  158. resp : TIdHTTPResponse;
  159. {$ENDIF}
  160. responsecontent : TStringStream;
  161. postcontent : TStringStream;
  162. begin
  163. postcontent := TStringStream.Create(Utf8Encode(aInContent));
  164. try
  165. //postcontent.WriteString(aInContent);
  166. responsecontent := TStringStream.Create('',TEncoding.UTF8);
  167. try
  168. {$IFDEF DELPHIXE8_UP}
  169. if aHeaders <> nil then
  170. begin
  171. for pair in aHeaders do
  172. begin
  173. headers := headers + [TNameValuePair.Create(pair.Name,pair.Value)];
  174. end;
  175. end;
  176. resp := fHTTPClient.Post(aURL,postcontent,responsecontent,headers);
  177. {$ELSE}
  178. if aHeaders <> nil then
  179. begin
  180. for pair in aHeaders do
  181. begin
  182. fHttpClient.Request.CustomHeaders.Values[pair.Name] := pair.Value;
  183. end;
  184. end;
  185. {$IFDEF FPC}
  186. try
  187. fHTTPClient.Post(aURL,postcontent,responsecontent);
  188. fHTTPClient.Disconnect(False);
  189. except
  190. on E : Exception do
  191. begin
  192. if e.ClassType <> EIdConnClosedGracefully then raise;
  193. end;
  194. end;
  195. {$ELSE}
  196. fHTTPClient.Post(aURL,postcontent,responsecontent);
  197. {$ENDIF}
  198. resp := fHTTPClient.Response;
  199. {$ENDIF}
  200. Result := THttpRequestResponse.Create(resp,responsecontent.DataString);
  201. finally
  202. responsecontent.Free;
  203. end;
  204. finally
  205. postcontent.Free;
  206. end;
  207. end;
  208. function TJsonHttpClient.Post(const aURL : string; aInContent : TStream) : IHttpRequestResponse;
  209. var
  210. {$IFDEF DELPHIXE8_UP}
  211. resp : IHTTPResponse;
  212. {$ELSE}
  213. resp : TIdHTTPResponse;
  214. {$ENDIF}
  215. responsecontent : TStringStream;
  216. begin
  217. //postcontent.WriteString(aInContent);
  218. responsecontent := TStringStream.Create('',TEncoding.UTF8);
  219. try
  220. {$IFDEF DELPHIXE8_UP}
  221. resp := fHTTPClient.Post(aURL,aInContent,responsecontent);
  222. {$ELSE}
  223. {$IFDEF FPC}
  224. try
  225. fHTTPClient.Post(aURL,aInContent,responsecontent);
  226. fHTTPClient.Disconnect(False);
  227. except
  228. on E : Exception do
  229. begin
  230. if e.ClassType <> EIdConnClosedGracefully then raise;
  231. end;
  232. end;
  233. {$ELSE}
  234. fHTTPClient.Post(aURL,aInContent,responsecontent);
  235. {$ENDIF}
  236. resp := fHTTPClient.Response;
  237. {$ENDIF}
  238. Result := THttpRequestResponse.Create(resp,responsecontent.DataString);
  239. finally
  240. responsecontent.Free;
  241. end;
  242. end;
  243. function TJsonHttpClient.Post(const aURL : string; aJsonContent : TJsonObject) : IHttpRequestResponse;
  244. begin
  245. {$IFDEF DELPHIXE8_UP}
  246. Result := Self.Post(aURL,aJsonContent.ToJSON);
  247. {$ELSE}
  248. {$IFDEF FPC}
  249. Result := Self.Post(aURL,aJsonContent.AsJson);
  250. {$ELSE}
  251. Result := Self.Post(aURL,aJsonContent.ToString);
  252. {$ENDIF}
  253. {$ENDIF}
  254. end;
  255. function TJsonHttpClient.Put(const aURL, aInContent : string) : IHttpRequestResponse;
  256. var
  257. {$IFDEF DELPHIXE8_UP}
  258. resp : IHTTPResponse;
  259. {$ELSE}
  260. resp : TIdHTTPResponse;
  261. {$ENDIF}
  262. responsecontent : TStringStream;
  263. postcontent : TStringStream;
  264. begin
  265. postcontent := TStringStream.Create(Utf8Encode(aInContent));
  266. try
  267. //postcontent.WriteString(aInContent);
  268. responsecontent := TStringStream.Create('',TEncoding.UTF8);
  269. try
  270. {$IFDEF DELPHIXE8_UP}
  271. resp := fHTTPClient.Put(aURL,postcontent,responsecontent);
  272. {$ELSE}
  273. {$IFDEF FPC}
  274. try
  275. fHTTPClient.Put(aURL,postcontent,responsecontent);
  276. fHTTPClient.Disconnect(False);
  277. except
  278. on E : Exception do
  279. begin
  280. if e.ClassType <> EIdConnClosedGracefully then raise;
  281. end;
  282. end;
  283. {$ELSE}
  284. fHTTPClient.Post(aURL,postcontent,responsecontent);
  285. {$ENDIF}
  286. resp := fHTTPClient.Response;
  287. {$ENDIF}
  288. Result := THttpRequestResponse.Create(resp,responsecontent.DataString);
  289. finally
  290. responsecontent.Free;
  291. end;
  292. finally
  293. postcontent.Free;
  294. end;
  295. end;
  296. procedure TJsonHttpClient.SetConnectionTimeout(const aValue: Integer);
  297. begin
  298. fConnectionTimeout := aValue;
  299. {$IFDEF DELPHIXE8_UP}
  300. {$IFDEF DELPHIRX102_UP} //in previous versions don't exists ConnectionTimeout property
  301. fHTTPClient.ConnectionTimeout := aValue;
  302. {$ENDIF}
  303. {$ELSE}
  304. fHTTPClient.ConnectTimeout := aValue;
  305. {$ENDIF}
  306. end;
  307. procedure TJsonHttpClient.SetContentType(const aValue: string);
  308. begin
  309. fContentType := aValue;
  310. {$IFDEF DELPHIXE8_UP}
  311. fHTTPClient.ContentType := aValue;
  312. {$ELSE}
  313. fHTTPClient.Request.ContentType := aValue;
  314. {$ENDIF}
  315. end;
  316. procedure TJsonHttpClient.SetHandleRedirects(const aValue: Boolean);
  317. begin
  318. fHandleRedirects := aValue;
  319. {$IFDEF DELPHIXE8_UP}
  320. fHTTPClient.HandleRedirects := aValue;
  321. {$ELSE}
  322. fHTTPClient.HandleRedirects := aValue;
  323. {$ENDIF}
  324. end;
  325. procedure TJsonHttpClient.SetResponseTimeout(const aValue: Integer);
  326. begin
  327. fResponseTimeout := aValue;
  328. {$IFDEF DELPHIXE8_UP}
  329. {$IFDEF DELPHIRX102_UP} //in previous versions don't exist ResponseTimeout property
  330. fHTTPClient.ResponseTimeout := aValue;
  331. {$ENDIF}
  332. {$ELSE}
  333. fHTTPClient.ReadTimeout := aValue;
  334. {$ENDIF}
  335. end;
  336. procedure TJsonHttpClient.SetUserAgent(const aValue: string);
  337. begin
  338. fUserAgent := aValue;
  339. {$IFDEF DELPHIXE8_UP}
  340. fHTTPClient.UserAgent := aValue;
  341. {$ELSE}
  342. fHTTPClient.Request.UserAgent := aValue;
  343. {$ENDIF}
  344. end;
  345. { THttpRequestResponse }
  346. {$IFDEF DELPHIXE8_UP}
  347. constructor THttpRequestResponse.Create(aResponse: IHTTPResponse; const aContent : string);
  348. begin
  349. fStatusCode := aResponse.StatusCode;
  350. fStatusText := aResponse.StatusText;
  351. if ((aContent <> '') and
  352. (aContent.StartsWith('{') or (aContent.StartsWith('[')))
  353. ) then fResponse := TJSONObject.ParseJSONValue(aContent) as TJSONObject;
  354. //if response is not json, get as json result
  355. if fResponse = nil then
  356. begin
  357. fResponse := TJSONObject.Create;
  358. fResponse.AddPair('Result',aContent);
  359. end;
  360. end;
  361. {$ELSE}
  362. constructor THttpRequestResponse.Create(aResponse : TIdHTTPResponse; const aContent : string);
  363. begin
  364. fStatusCode := aResponse.ResponseCode;
  365. fStatusText := aResponse.ResponseText;
  366. {$If Defined(FPC) OR Defined(DELPHIXE8_UP)}
  367. if (aContent.Contains('{')) and (aContent.Contains('}')) then fResponse := GetJSON(aContent) as TJsonObject;
  368. {$ELSE}
  369. if (aContent.Contains('{')) and (aContent.Contains('}')) then fResponse:= TJsonObject.ParseJSONValue(aContent) as TJsonObject;
  370. {$ENDIF}
  371. //if response is not json, get as json result
  372. if fResponse = nil then
  373. begin
  374. fResponse := TJSONObject.Create;
  375. {$IFDEF DELPHIXE4_UP}
  376. fResponse.AddPair('Result',aContent);
  377. {$ELSE}
  378. fResponse.Add('Result',aContent);
  379. {$ENDIF}
  380. end;
  381. end;
  382. {$ENDIF}
  383. destructor THttpRequestResponse.Destroy;
  384. begin
  385. if Assigned(fResponse) then fResponse.Free;
  386. inherited;
  387. end;
  388. function THttpRequestResponse.Response: TJSONObject;
  389. begin
  390. Result := fResponse;
  391. end;
  392. function THttpRequestResponse.StatusCode: Integer;
  393. begin
  394. Result := fStatusCode;
  395. end;
  396. function THttpRequestResponse.StatusText: string;
  397. begin
  398. Result := fStatusText;
  399. end;
  400. end.