解决USDA ESMIS API的Bad Request错误——Python requests调用问题
Let's break down why your curl command works but your Python code doesn't, and fix it step by step.
The Root Cause
When you use curl with -d '{"auth": {...}}' and set Content-Type: application/json, you're sending a raw JSON string as the request body. But in your original Python code, passing a dictionary to the data parameter tells Requests to encode it as application/x-www-form-urlencoded (form data) instead of JSON—even if you manually set the Content-Type header. The USDA API expects JSON, so it rejects the mismatched form data with a 400 error.
The Fix: Use the json Parameter
Requests has a built-in json parameter that handles both serializing your dictionary to JSON and setting the correct Content-Type: application/json header automatically. Here's the corrected code:
import requests import getpass email = "r******@gmail.com" password = getpass.getpass() data = {"auth": {"email": email, "password": password}} url = "https://usda.library.cornell.edu/user_token" # Use the json parameter instead of data response = requests.post(url, json=data) print(f"Status Code: {response.status_code}") # Check the actual error message from the server (critical for debugging!) if response.status_code != 200: print("Server Error Message:", response.text) else: print("Success! Token:", response.json())
If You Still Run Into Issues
If you tried the json parameter and it didn't work, here are quick troubleshooting checks:
- Verify credentials: Temporarily print the
datadictionary (don't commit this to code!) to make sure the email and password fromgetpassare correctly captured. - Check for special characters: If your password has characters like
&,=, or quotes,jsonensures they're properly escaped in the request—something form encoding might mangle. - Avoid conflicting headers: When using
json, you don't need to manually setContent-Type—Requests does it for you. If you add the header anyway, double-check for typos (e.g.,application/jsonis spelled correctly).
Alternative: Manual JSON Serialization
If you prefer to use data (not recommended, but for completeness), you need to manually serialize the dictionary to a JSON string with json.dumps:
import json import requests import getpass email = "r******@gmail.com" password = getpass.getpass() data = {"auth": {"email": email, "password": password}} headers = {"Content-Type": "application/json"} url = "https://usda.library.cornell.edu/user_token" response = requests.post(url, data=json.dumps(data), headers=headers)
Always check response.text when you get a 400 error—it will usually tell you exactly what the server is missing or rejecting (e.g., "invalid JSON format" or "missing auth fields").
内容的提问来源于stack exchange,提问作者Rutger Hofste

