我已经设置了一个 RESTlet API,用于从 NetSuite 中的“保存的交易搜索”获取订单数据。在生产中,它工作得非常完美。现在我需要根据NetSuite的订单数据完成更多功能。在不影响生产的情况下,我开始在沙盒中设计新的功能。在生产中完美运行的 API 仅在沙箱中返回 []。
我尝试过重做集成,并进行访问,并检查了所有ID,但无法找出问题所在。
这里是打印订单数据的代码:
import time
import uuid
import urllib.parse
import hmac
import hashlib
import base64
import requests
def generate_oauth_signature(method, url, consumer_key, consumer_secret, token_id, token_secret, realm=""):
params = {
'oauth_consumer_key': consumer_key,
'oauth_nonce': uuid.uuid4().hex,
'oauth_signature_method': 'HMAC-SHA256',
'oauth_timestamp': str(int(time.time())),
'oauth_token': token_id,
'oauth_version': '1.0',
}
url_parts = urllib.parse.urlparse(url)
query_params = urllib.parse.parse_qs(url_parts.query)
for key, value in query_params.items():
params[key] = value[0]
sorted_params = sorted(params.items())
base_string = method.upper() + '&' + urllib.parse.quote_plus(url_parts.scheme + '://' + url_parts.netloc + url_parts.path) + '&' + urllib.parse.quote_plus('&'.join([urllib.parse.quote_plus(k) + '=' + urllib.parse.quote_plus(v) for k, v in sorted_params]))
signing_key = urllib.parse.quote_plus(consumer_secret) + '&' + urllib.parse.quote_plus(token_secret)
signature = hmac.new(signing_key.encode(), base_string.encode(), hashlib.sha256).digest()
oauth_signature = base64.b64encode(signature).decode()
auth_header = 'OAuth realm="' + realm + '", '
auth_header += 'oauth_consumer_key="' + urllib.parse.quote_plus(consumer_key) + '", '
auth_header += 'oauth_token="' + urllib.parse.quote_plus(token_id) + '", '
auth_header += 'oauth_signature_method="HMAC-SHA256", '
auth_header += 'oauth_timestamp="' + params['oauth_timestamp'] + '", '
auth_header += 'oauth_nonce="' + params['oauth_nonce'] + '", '
auth_header += 'oauth_version="1.0", '
auth_header += 'oauth_signature="' + urllib.parse.quote_plus(oauth_signature) + '"'
return auth_header
def fetch_netsuite_orders():
#This is for production
'''
netsuite_url = "https://11111111.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
consumer_key = "11111111"
consumer_secret = "11111111"
token_id = "11111111"
token_secret = "111111111"
realm = "11111111"
'''
#This is for sandbox
netsuite_url = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
consumer_key = "11111111"
consumer_secret = "11111111"
token_id = "11111111"
token_secret = "11111111"
realm = "11111111_SB1"
auth_header = generate_oauth_signature("GET", netsuite_url, consumer_key, consumer_secret, token_id, token_secret, realm)
#print(auth_header)
headers = {
'Authorization': auth_header,
'Content-Type': 'application/json',
}
response = requests.get(netsuite_url, headers=headers)
if response.status_code == 200:
#print("Success")
#print(response.json())
return response.json()
else:
print(f"Failed to fetch orders, status code: {response.status_code}")
print(response.text)
return []
def fetch_orders():
orders_data = fetch_netsuite_orders()
return orders_data
if __name__ == "__main__":
orders_data = fetch_orders()
print(orders_data)
API 代码如下:
/**
* @NApiVersion 2.x
* @NScriptType Restlet
*/
define(['N/search'], function(search) {
function doGet(requestParams) {
var searchId = 'customsearch696000';
var searchResults = [];
var mySearch = search.load({
id: searchId
});
var resultSet = mySearch.run();
var searchIndex = 0;
var result;
do {
result = resultSet.getRange({
start: searchIndex,
end: searchIndex + 1000
});
if (result && result.length > 0) {
searchResults = searchResults.concat(result);
searchIndex += result.length;
}
} while (result && result.length == 1000);
return searchResults;
}
return {
'get': doGet
};
});
您的问题至少有一部分是由于签名生成不正确...... 仅使用 baseUrl 生成签名:https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl,并在生成“params”时使用查询参数(在按字母顺序排列),因此只需在调用“generate_oauth_signature”函数之前将它们分开即可:
#This is for sandbox
netsuite_url = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=111&deploy=1"
baseUrl = "https://11111111-sb1.restlets.api.netsuite.com/app/site/hosting/restlet.nl"
scriptId = "111"
deployId = "1"
.
.
.
auth_header = generate_oauth_signature("GET", baseUrl, scriptId, deployId, consumer_key, consumer_secret, token_id, token_secret, realm)
def generate_oauth_signature(method, baseUrl, scriptId, deployId, consumer_key, consumer_secret,
token_id, token_secret, realm=""):
params = {
'deploy': deployId,
'oauth_consumer_key': consumer_key,
'oauth_nonce': uuid.uuid4().hex,
'oauth_signature_method': 'HMAC-SHA256',
'oauth_timestamp': str(int(time.time())),
'oauth_token': token_id,
'oauth_version': '1.0',
'script': scriptId
}
但生成签名后仍使用请求的完整 url。还, 对于某些 Netsuite 调用,需要 Prefer 'transient' 标头:
headers = {
'Authorization': auth_header,
'Prefer', "transient" ,
'Content-Type': 'application/json',
}
response = requests.get(netsuite_url, headers=headers)
此外,直接在标头中指定 Content-Type 有时可能会导致 Netsuite 出现错误。我主要通过 api 与 c# 进行通信,因此这可能与您的代码有所不同。因为我只指定了 application/json 的内容类型,所以只指定了我发送的有效负载。仅供参考。祝你好运!