C-Sharp
Gemini API 讀取響應/內容?
所以我正在嘗試測試來自 Gemini 的經過驗證的響應。我得到了一個“響應”,但不是我所期望的……它以 html 字元串的形式返回,而不是API 建議我應該得到的“餘額數組” 。我以前沒有使用過 HttpClient,所以這裡的學習曲線是雙重的。不確定我是否有錯誤的資訊,或者我是否正在查看錯誤的方法/屬性?
對於如何從 Gemini 返回這個數組,我有點困惑。
我在那裡有 API 密鑰和秘密,因為這只是在沙盒上。帳戶有大約 1,000,000 個假資產。
JSON字元串
{"request":"/v1/balances","nonce":1477275934999}
JSON / Payload 的 Base64 編碼
eyJyZXF1ZXN0IjoiL3YxL2JhbGFuY2VzIiwibm9uY2UiOjE0NzcyNzU5MzQ5OTl9
留言
Method: POST, RequestUri: 'https://api.sandbox.gemini.com/', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { X-GEMINI-APIKEY: L6qDKmQZcmLVDTd5zK9S X-GEMINI-PAYLOAD: eyJyZXF1ZXN0IjoiL3YxL2JhbGFuY2VzIiwibm9uY2UiOjE0NzcyNzU5MzQ5OTl9 X-GEMINI-SIGNATURE: DBA15C6B2FFA602F9323E0180A14BABEA018640324E313D6C8BBAE9F8872B06325B75F6C507C55435982D600EE5DDF57 Content-Type: text/plain; charset=utf-8 }
響應字元串:(似乎總是“工作”,即使我有格式錯誤的請求,我也沒有註意到)
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { Connection: keep-alive Age: 6605 X-Cache: Hit from cloudfront X-Amz-Cf-Id: Ae3ps4mhbjIzGCrgFr43dq0ICZvnUmPKpeo1miv4ufDFJkJtNZy8GA== Date: Sat, 22 Oct 2016 22:55:51 GMT ETag: "5dc6bbdccdd2100c4ca4b0155402db35" Server: AmazonS3 Via: 1.1 cae81d5ff1d682b28f2deabdd94777d4.cloudfront.net (CloudFront) Content-Length: 172 Content-Type: text/html Last-Modified: Fri, 29 Jul 2016 18:31:06 GMT }
Response.Content - 不是我所期望的……
<html> <head> <script> window.location.replace("/rest-api/" + window.location.search + window.location.hash); </script> </head> </html>
程式碼(C# .NET 4.5)
using System; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using Gemini.API; using Newtonsoft.Json; namespace HodlBot { class Program { public const int TIME_INTERVAL_IN_MILLISECONDS = 3000; private static Timer m_timer = null; private static void Main(string[] args) { var source = new CancellationTokenSource(); Console.CancelKeyPress += (s, e) => { e.Cancel = true; source.Cancel(); }; m_timer = new System.Threading.Timer(Tick, source, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite); source.Token.WaitHandle.WaitOne(); } private async static void Tick(object p_state) { Console.Clear(); var c = (CancellationTokenSource)p_state; /* All requests must contain a nonce, a number that will never be repeated and must increase between requests. This is to prevent an attacker who has * captured a previous request from simply replaying that request. We recommend using a millisecond-level timestamp. The nonce need only be * increasing with respect to the session that the message is on.*/ long nonce = DateTimeOffset.Now.ToUnixTimeMilliseconds(); string jObject = JsonConvert.SerializeObject(new Balance(nonce)); await POST(jObject); // Re-Prime Event if(!c.Token.IsCancellationRequested) m_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite); } private static async Task POST(string jsonText) { // Sign Payload Console.WriteLine(jsonText); string payload = System.Convert.ToBase64String((Encoding.UTF8.GetBytes(jsonText))); Console.WriteLine(payload); HMACSHA384 hmac = new HMACSHA384(Encoding.UTF8.GetBytes("LixWGpx3h89D8B4uQvfxd8hy5N1")); //My API SECRET byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(payload)); string hexHash = BitConverter.ToString(hash).Replace("-", ""); using(var httpClient = new HttpClient()) using(var stringContent = new StringContent("", Encoding.UTF8, "text/plain")) using(var r = new HttpRequestMessage(HttpMethod.Post, "https://api.sandbox.gemini.com")) { r.Headers.Add("X-GEMINI-APIKEY", "L6qDKmQZcmLVDTd5zK9S"); r.Headers.Add("X-GEMINI-PAYLOAD", payload); r.Headers.Add("X-GEMINI-SIGNATURE", hexHash); r.Content = stringContent; Console.WriteLine(r.ToString()); var response = await httpClient.SendAsync(r); if(response.IsSuccessStatusCode) { Console.WriteLine(response.ToString()); var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(content); } } } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace Gemini.API { public class BasicRequest { [JsonProperty("request", Order = 1)] public string Request { get; internal set; } [JsonProperty("nonce", Order = 2)] public long Nonce { get; internal set; } public BasicRequest(string request, long nonce) { Request = request; Nonce = nonce; } } public class HeartBeat : BasicRequest { public HeartBeat(long nonce) : base("/v1/heartbeat", nonce) { } } public class Balance : BasicRequest { public Balance(long nonce) : base("/v1/balances", nonce) { } } }
除了
request
在有效負載中設置參數之外,您還需要向正確的 URI 發出 POST 請求。所以你寫的地方:
using(var r = new HttpRequestMessage(HttpMethod.Post, "https://api.sandbox.gemini.com")) { ... }
你需要類似的東西:
var request = "/v1/balances"; // or whatever endpoint you're trying to use var url = "https://api.sandbox.gemini.com" + request; using(var r = new HttpRequestMessage(HttpMethod.Post, url)) { ... }