使用JavaScript URL 模拟 JSONP 响应

15
我在WP网站上使用Gravity Forms。我的表单通过Pardot的表单处理程序(form handlers)通过ajax提交到Pardot。我遇到了一个问题,即Pardot处理表单6次,没有其他错误。研究表明,这是因为Pardot不支持CORS或JSONP,因此在使用ajax提交时陷入循环中。它正在处理提交数据,但从未“完成”,当表单处理程序的Success URL设置为引荐URL时。它尝试6次后放弃,在每次处理提交的数据并发送新的潜在客户通知电子邮件。
Pardot的帮助文档提供了以下解决方案:

可以通过将表单处理程序的成功和错误URL设置为执行成功和错误回调的JavaScript URL来模拟JSONP响应。

我不太确定这是什么意思或如何处理它。我在stackoverflow和google上查找了一些资料,但似乎无法理解如何实现它。能否有人帮助澄清这个概念或指导我正确的方向?
谢谢!
4个回答

7
EDIT:经过几天的努力,我将发布最终解决方案,这可能有助于其他人使用JSONP与Pardot进行通信。这是一个三部分的问题:
  1. 向Pardot表单处理程序发送JSONP请求
  2. 重定向Pardot表单处理程序成功/错误到您自己的服务器
  3. 从您的服务器返回JSONP

向Pardot From Handler发送JSONP请求

要将表单数据发送到表单处理程序,您需要对字段名称和值进行URI编码。

(使用JQuery的示例。当指定dataType: 'jsonp'时,ajax()会添加“?callback=”):

var data = { 'field1' = 'value1', 'field' = 'value2' };
var uriEncodedParams = $.param(data);
var targetUrl = <Pardot Form Handler URL> + '?' + uriEncodedParams;

$.ajax({
    url: targetUrl,
    dataType: 'jsonp',
    jsonpCallback: 'callback'
});

window.callback = function (data) {...}

将Pardot从处理程序成功/错误重定向到您自己的服务器

请参见@nickjag的答案:

将成功位置和错误位置设置为后端上的终点。

由于pardot不会转发您传递的任何GET参数,因此您必须在回调函数名称上使用一些默认值(因此在我的请求中指定jsonpCallback而没有成功)。

从您的服务器返回JSONP

当我使用return "{ 'result' : 'success' }"时,我遇到了控制台错误(Uncaught SyntaxError: Unexpected token :),因为它是一个JSON对象,而JSONP需要一个JavaScript文件。因此,返回的格式应该是:return "callback({ 'result' : 'success' })"

由于Pardot不会转发GET参数,因此JQuery生成的回调函数名称没有传播,因此我无法返回正确的JavaScript代码。如果未提供,则默认使用函数名“callback”。

返回.NET MVC后端的JSONP指南


谢谢,这也非常有帮助!我已经尝试了@nickjag和你的方法,它们都有效! - alison

4
Pardot建议您在自己的服务器上创建2个静态URL,返回一个简单的JSON响应。
例如:
1. mysite.com/pardot-success
返回:{"result":"success"}
2. mysite.com/pardot-error
返回:{"result":"error"}
您将使用这两个URL作为Pardot表单处理程序设置中的成功和错误重定向URL。
然后,可以使用JSONP对您的Pardot表单处理程序进行AJAX请求,它将包装并返回其中一个URL的JSON响应(取决于结果)。
您的AJAX响应数据将包括JSON结果(成功或错误)。

非常感谢。这确实让我朝着正确的方向前进了。 - alison
那么我需要在后端创建两个文件吗? - TaouBen

0
所有这里的答案真的帮助了我开始解决这个问题,但我的要求是只通过Salesforce实现一切工作。所以对于任何只使用Salesforce后端架构寻找答案的人,我希望这对你有所帮助。为了使它正常工作,我不得不稍微改变我的Ajax调用结构。
var data = { 'username': username };
var uriEncodedParams = $.param(data);
var targetUrl = 'https://my.pardot.url' + '?' + uriEncodedParams;
$.ajax({
    url: targetUrl,
    type: 'GET',
    dataType: 'jsonp',
    crossDomain: true
});

window.callback = function(data) {
    performMoreActions(data);
}

我的服务器是用Apex(Salesforce的编程语言)构建的,它看起来像这样:

@RestResource(urlMapping='/pardot/success/*')
global without sharing class Pardot_SuccessProxy {

    @HttpGet
    global static void Pardot_SuccessProxy() {
        RestContext.response.addHeader('Content-Type', 'application/json');
        RestContext.response.responseBody = (Blob.valueOf('callback({ "result" : "success" })'));
    }
}

然后我通过Salesforce SITE将这个REST webservice公开,URL类似于:

https://my-domain.server-domain.force.com/services/apexrest/pardot/success

https://my-domain.server-domain.force.com/services/apexrest/pardot/error

在Pardot表单处理程序UI中,将成功位置和错误位置字段分别设置为这些URL。
这与此问题的其他答案非常相似,但采用了完全基于Salesforce的方法。它可能与OP的技术堆栈有些不相关,但对于未来寻找答案的人应该是有帮助的。

0

感谢这里所有的答案,在一天的头痛之后,我终于想出了如何使用原生JS(使用Vue)使其工作。我想在这里发布帖子,以帮助避免任何可怜的灵魂经历同样的挫折。

成功/错误的JS文件应该在同一个域上

success.js:

logResult({ result: 'success' });

error.js:

logResult({ result: 'error' });

将这些URL添加到Pardot表单处理程序中的“成功位置”和“错误位置”字段中

Jsonp函数

我使用vue构建了这个网站,所以我将下面的函数添加到/asses/js/util.js中

//  Copyright (c) 2017 Ziqiang Li - copied and edited from https://github.com/liziqiang/simple-jsonp-promise/blob/master/src/index.js
// Callback index.
let count = 0;

function jsonp(url, options) {
  options = options || {};
  const prefix = options.prefix || 'logResult';
  const callback = options.callback || 'callback';
  const callbackName = options.callbackName;
  const params = options.data || {};
  const target = document.getElementsByTagName('script')[0] || document.head;
  let script;
  let timer;
  // Generate a unique id for the request.
  const id = callbackName || prefix + count++;

  function noop() {}

  function cleanup() {
    // Remove the script tag.
    if (script && script.parentNode) {
      script.parentNode.removeChild(script);
    }
    window[id] = noop;
    if (timer) {
      clearTimeout(timer);
    }
  }

  function serialize(params) {
    let param = '';
    for (const key in params) {
      if (params.hasOwnProperty(key)) {
        param += `&${key}=${encodeURIComponent(params[key])}`;
      }
    }
    return param;
  }

  function handleUrl(url, params) {
    if (!~url.indexOf('?')) { url += '?'; }
    url += serialize(params);
    url = url.replace('?&', '?');
    return url;
  }

  return new Promise((resolve, reject) => {
    window[id] = function(data) {
      cleanup();
      resolve(data);
    };
    if (!callbackName) {
      params[callback] = id;
    }
    url = handleUrl(url, params);
    // Create script.
    script = document.createElement('script');
    script.src = url;

    window.logResult = function(json) {
      if (json.result === 'success') {
        resolve();
      } else if (json.result === 'error') {
        reject(new Error('Error'));
      }
    };

    script.onerror = function() {
      cleanup();
      reject(new Error('Network Error'));
    };
    target.parentNode.insertBefore(script, target);
  });
}

export default jsonp;

注意:回调函数名称(logResult)需要与成功/错误JS文件中的函数名称相同。
提交函数
我的Vue组件中的脚本(应易于转移到原生JS /其他框架):
<script>
import jsonp from '@/assets/js/util';

export default {
  name: 'FormTest',

  data() {
    return {
      firstname: '',
      lastname: '',
      email: '',
    };
  },

  methods: {
    submit() {
      const options = {
        data: {
          firstname: this.firstname,
          lastname: this.lastname,
          email: this.email,
        },
      };

      jsonp('PARDOT_FORM_HANDLER_URL', options).then(() => {
        console.log('success');
      }).catch(err => {
        console.error(err);
      });
    },
  },
};
</script>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接