Insightly CRM Ajax API 代理

Insightly CRM Ajax API proxy

更新

您好,我目前在尝试连接到 Insightlys CRM API 时遇到 CORS 错误。我正在通过 POSTMAN 成功检索我的 Insightly CRM 数据。

Insightly 不支持 AJAX 请求 (http://support.insight.ly/hc/en-us/community/posts/206961417-Using-the-API-with-AJAX) 的 CORS,您必须设置 API 代理脚本。我使用了在 python 中完成的以下提供的代理脚本并上传到我的专用主机。但是我仍然收到 401 错误?

我对 API 代理很陌生,所以不确定我是否遗漏了什么?

GET https://api.insight.ly/v2.2/Contacts 401 (Unauthorized)

apiproxy.py

#
# Insightly API Proxy for Python / App Engine
# Brian McConnell <brian@insightly.com>
#
# This utility is designed to act as an API proxy server. It is written in  Python 2.7
# and will run without modification on Google App Engine. Just serve your JavaScript
# from the /js directory in this project, and AJAX requests should be relayed through
# to the Insightly service. This should also run on any webapp2 compatible server platform
#

import base64
import os
import string
import types
import urllib
import urllib2
import webapp2
import wsgiref.handlers

#
# import google app engine libraries, replace these with standard 
#

try:
    from google.appengine.ext import webapp
except:
# skip Google App Engine webapp library
    pass

base_url = 'https://api.insight.ly/v2.2'

def authenticate():
#
# add user validation logic here, be careful to do this in a way that does not expose user secrets such as
# the user API key (this is why we do not allow CORS in the first place)
#

# hardcoding API key for now

apikey = 'fillinhere'
return base64.encode(apikey)

def generateRequest(url, method, data, alt_auth=None, test=False, headers=None):
"""
This method is used by other helper functions to generate HTTPS requests and parse server responses. This will minimize the amount of work developers need to do to integrate with the Insightly API, and will also eliminate common sources of errors such as authentication issues and malformed requests. Uses the urllib2 standard library, so it is not dependent on third party libraries like Requests
"""
if type(url) is not str: raise Exception('url must be a string')
if type(method) is not str: raise Exception('method must be a string')
valid_method = False
response = None
text = ''
if method == 'GET' or method == 'PUT' or method == 'DELETE' or method == 'POST':
valid_method = True
else:
raise Exception('parameter method must be GET|DELETE|PUT|UPDATE')
request = urllib2.Request(url)
request.get_method = lambda: method
request.add_header('Content-Type', 'application/json')
if headers is not None:
headerkeys = headers.keys()
for h in headerkeys:
    request.add_header(h, headers[h])
# open the URL, if an error code is returned it should raise an exception
if method == 'PUT' or method == 'POST':
result = urllib2.urlopen(request, data)
else:
result = urllib2.urlopen(request)
text = result.read()
return text

class APIProxyHandler(webapp2.RequestHandler):

def delete(self):
    apikey = authenticate()
    path_qs = self.request.headers['path_qs']
    url = base_url + path_qs
    headers = {'Authorization','Basic ' + api_key}
    text = generateRequest(url, 'DELETE', None, headers=headers)
    self.response.headers['Content-Type']='application/json'
    self.response.out.write(text)
def get(self):
    apikey = authenticate()
    path_qs = self.request.headers['path_qs']
    url = base_url + path_qs
    headers = {'Authorization','Basic ' + api_key}
    text = generateRequest(url, 'GET', None, headers=headers)
    self.response.headers['Content-Type']='application/json'
    self.response.out.write(text)
def post(self):
    body = self.request.headers['body']
    path_qs = self.request.headers['path_qs']
    url = base_url + path_qs
    headers = {'Authorization','Basic ' + api_key}
    text = generateRequest(url, 'POST', body, headers=headers)
    self.response.headers['Content-Type']='application/json'
    self.response.out.write(text)
def put(self):
    body = self.request.headers['body']
    path_qs = self.request.headers['path_qs']
    url = base_url + path_qs
    headers = {'Authorization','Basic ' + api_key}
    text = generateRequest(url, 'PUT', body, headers=headers)
    self.response.headers['Content-Type']='application/json'
    self.response.out.write(text)

app = webapp2.WSGIApplication([("r/(.*)", APIProxyHandler)], debug=True)
# map generic page server request handler

jQuery/Ajax 通话:

Insightly = function () {
var _t = this;

this.events = function () {
    $(".contactsform").submit(_t.searchContacts);
};
this.searchContacts = function (event) {
event.preventDefault();
var $search = $(this);
console.log('[ Search contacts event ]');

$.ajaxPrefilter( function( options ) {
    if ( options.crossDomain ) {
    var newData = {};

    newData.data = $.extend({}, options.data);
    newData.url = options.url;

    options = {};

    // Set the proxy URL
    options.url = "http://www.blahblah.comm/apiproxy.py";
    console.log("ajaxprefilter");
    options.data = $.param(newData);
    console.log(options);
    options.crossDomain = false;
}
});
// How to use the cross domain proxy
$.ajax({         
    url: 'https://api.insight.ly/v2.2/Contacts',
    crossDomain: true, 
    processData: false 
    }).success(function(data) { 
    var jsonData = JSON.parse(data); 
    console.log(jsonData); 
});
};//End SearchContacts
this.init = function () {
    _t.events();
};
this.init();
return (this);   
};//End main function
var LZ = new Insightly();

非常感谢您的帮助。

这意味着您无法使用来自 client-side 的 AJAX 或 javascript http 请求直接访问他们的 API。您需要做的是创建一个 "Proxy" API。

A "Proxy" API 是您需要在客户端代码所在的域中托管的服务。您需要使用您最喜欢的 server-side 语言编写对 Insightly CRM API 的经过身份验证的 server-side API 调用,并使用您的 jquery AJAX 调用它。

所以下面的代码将是:

var searchNotesUrl = "https://myowndomain.com/your/api/proxy/notes"

换句话说,您的 server-side 脚本将是将数据从 CRM API 中继到您的客户的脚本。

如果它仍然收到 401 响应,那么您可能需要检查用户和 API 密钥凭据是否正确。

更新

你现在完全改变了问题。我上面的回答是针对你的最后一个问题版本。

对于新答案,您对这段代码有疑问:

$.ajaxPrefilter( function( options ) {
    if ( options.crossDomain ) {
    var newData = {};

    newData.data = $.extend({}, options.data);
    newData.url = options.url;

    options = {};

    // Set the proxy URL
    options.url = "http://www.blahblah.comm/apiproxy.py";
    console.log("ajaxprefilter");
    options.data = $.param(newData);
    console.log(options);
    options.crossDomain = false;
}
});
// How to use the cross domain proxy
$.ajax({         
    url: 'https://api.insight.ly/v2.2/Contacts',
    crossDomain: true, 
    processData: false 
    }).success(function(data) { 
    var jsonData = JSON.parse(data); 
    console.log(jsonData); 
});

首先,您仍在向 'https://api.insight.ly/v2.2/Contacts' 请求。您不需要再请求此 URL,因为您已经拥有代理 api。代理 api ("http://www.blahblah.comm/apiproxy.py") 是您应该直接调用的代理,而不是向 insight.ly.

发送请求

您的代理 API,应该处理可以在 insight.ly 中发送的所有 api 请求。这意味着 "http://www.blahblah.comm/apiproxy.py" 可以支持 notes , Contacts

其次,您可以阅读 python 脚本,它实际上查找请求 header 键 'path_qs'path_qs 值应该类似于 /Contacts。原因是因为 path_qs 通过 url = base_url + path_qs.

在脚本中与 base_url = 'https://api.insight.ly/v2.2' 连接

所以代码应该是这样的:

$.ajax({ 
   method: 'GET', //this is because it is supposed to be GET
   crossDomain: true,
   dataType: 'json',
   url: 'http://www.blahblah.comm/apiproxy/that/executes', 
   headers: { 'path_qs': '/Contacts' },
   success : function(data, status, xhr) {
      console.log(data);
   }
});

您需要在 Google 应用引擎云中将 Python 脚本设置为应用程序。要了解更多信息,这是一个全新的主题: https://cloud.google.com/appengine/docs/python/gettingstartedpython27/helloworld