Python调用Poloniex API返回422错误,求排查余额查询接口问题
A 422 Unprocessable Entity error usually means your request is structurally valid, but the server can’t process it—most often due to invalid parameters, encoding mishaps, or endpoint mismatches. Let’s break down the most likely issues with your code and how to fix them:
Common Issues & Fixes
1. Incorrect API Endpoint
Double-check that self.SETTINGS.BASE_URI + self.SETTINGS.TRADE_DIR points to Poloniex’s valid private trading API endpoint: https://poloniex.com/tradingApi. A frequent mistake is using the public API path (like /public) instead of the private trading endpoint, or having typos in the URL (e.g., extra slashes, missing segments).
2. Nonce Generation Problems
Poloniex requires the nonce to be a strictly increasing integer. While int(time.time() * 1000) works for most cases, issues can pop up if:
- Your system clock is out of sync (too far behind the server’s time)
- You previously sent a request with a higher nonce (e.g., testing with a manual nonce that’s larger than the timestamp-based value)
- The nonce gets truncated or converted incorrectly (make sure it’s a plain integer, not a string)
Log the nonce value before sending the request to confirm it’s a valid, increasing number.
3. Signature Generation Mistakes
Your HMAC-SHA512 signature needs to be generated precisely using the raw POST data and your private key. Watch for these pitfalls:
- Ensure your private key is encoded to bytes correctly. If
self.SETTINGS.PRIVATE_KEYis a string,str.encode()uses UTF-8 by default (which is correct)—but double-check there are no extra spaces or typos in your key (copy-paste errors are super common!). - Verify the
post_datapassed tohmac.new()is exactly the URL-encoded bytes sent in the request. Logpost_data.decode('utf-8')to confirm it looks likecommand=returnBalances&nonce=1234567890123.
4. Request Header Formatting
Poloniex expects the Key and Sign headers to be set properly:
- Confirm
self.SETTINGS.PUBLIC_KEYis your valid API public key (no missing characters or typos) - The
Signheader must be the hexadecimal digest of the HMAC signature—your code uses.hexdigest()correctly, but make sure the signature string isn’t accidentally modified before setting it in the header.
5. Encoding Edge Cases
While urllib.parse.urlencode().encode() should produce valid application/x-www-form-urlencoded data, try explicitly specifying UTF-8 encoding to rule out platform-specific issues:
post_data = urllib.parse.urlencode(polo_data).encode('utf-8')
Debugging Tips
Add logging to inspect full request details—this will help you spot discrepancies quickly:
# Log request metadata before sending print(f"Request URL: {self.SETTINGS.BASE_URI + self.SETTINGS.TRADE_DIR}") print(f"POST Data: {post_data.decode('utf-8')}") print(f"Headers: {headers}") print(f"Nonce: {polo_data['nonce']}")
You can also capture the full error response from Poloniex—they often include a message explaining exactly what’s wrong:
try: with urllib.request.urlopen(req) as response: print(response.read().decode('utf-8')) except urllib.error.HTTPError as e: print(f"Error Code: {e.code}") print(f"Error Response: {e.read().decode('utf-8')}")
Example Modified Code
Here’s your code with added error handling and logging to simplify debugging:
import time import urllib.parse import urllib.request import hmac import hashlib def getBalance(self): try: polo_data = {"command": "returnBalances", "nonce": int(time.time() * 1000)} post_data = urllib.parse.urlencode(polo_data).encode('utf-8') # Log request details for debugging print(f"POST Data: {post_data.decode('utf-8')}") print(f"Nonce: {polo_data['nonce']}") sig = hmac.new(str.encode(self.SETTINGS.PRIVATE_KEY), post_data, hashlib.sha512).hexdigest() headers = {"Key": self.SETTINGS.PUBLIC_KEY, "Sign": sig} request_url = self.SETTINGS.BASE_URI + self.SETTINGS.TRADE_DIR print(f"Request URL: {request_url}") req = urllib.request.Request(request_url, data=post_data, headers=headers) with urllib.request.urlopen(req) as response: balance_data = response.read().decode('utf-8') print("Balance Response:", balance_data) return balance_data except urllib.error.HTTPError as e: print(f"HTTP Error {e.code}: {e.read().decode('utf-8')}") except Exception as e: print(f"Unexpected Error: {str(e)}")
内容的提问来源于stack exchange,提问作者Alex

