简体   繁体   English

使用 JavaScript 个 URL 模拟 JSONP 响应

[英]Simulate a JSONP response with JavaScript URLs

I'm using Gravity Forms on a WP site.我在 WP 网站上使用 Gravity Forms。 My forms POST via ajax to Pardot using Pardot form handlers .我的forms使用 Pardot 表单处理程序通过 ajax POST 到 Pardot。 I am running into an issue where Pardot processes the form 6x, with no other errors.我遇到了一个问题,Pardot 处理表单 6x,没有其他错误。 Research indicates that this is because Pardot does not support CORS or JSONP, and thus gets stuck in a loop when using ajax to submit.研究表明,这是因为Pardot不支持CORS或JSONP,因此在使用ajax提交时陷入了循环。 It's processing the submission but never "finishing" when the form handler's Success URL is set as referring URL. It tries 6x before giving up, processing the submitted data and sending new prospect notification emails each time.当表单处理程序的成功 URL 设置为引用 URL 时,它正在处理提交但从未“完成”。它在放弃之前尝试 6 次,处理提交的数据并每次发送新的潜在客户通知电子邮件。

Pardot help docs suggest the following solution: Pardot 帮助文档建议采用以下解决方案:

It is possible to simulate a JSONP response by setting the Success and Error URLs for the form handler to be JavaScript URLs that execute Success and Error callbacks, respectively.可以通过将表单处理程序的成功和错误 URL 设置为分别执行成功和错误回调的 JavaScript URL 来模拟 JSONP 响应。

I'm not totally sure what this means or how to approach it.我不完全确定这意味着什么或如何处理它。 I've done some stackoverflowing and googling, but I can't seem to wrap my head around how to do it.我已经完成了一些 stackoverflowing 和谷歌搜索,但我似乎无法全神贯注于如何去做。 Can someone help clarify this concept or point me in the right direction?有人可以帮助澄清这个概念或指出正确的方向吗?

Thanks!谢谢!

EDIT: So, after a few days battling with this I'll post my final solution that might help others trying to communicate with Pardot using JSONP.编辑:因此,在与此斗争几天后,我将发布我的最终解决方案,该解决方案可能会帮助其他人尝试使用 JSONP 与 Pardot 进行通信。 It's a three part problem:这是一个三部分的问题:

  1. Send a JSONP request to a Pardot Form Handler向 Pardot 表单处理程序发送 JSONP 请求
  2. Redirect Pardot Form Handler success/error to your own server将 Pardot 表单处理程序成功/错误重定向到您自己的服务器
  3. Return JSONP from your server从您的服务器返回 JSONP

Send a JSONP request to Pardot From Handler从处理程序向 Pardot 发送 JSONP 请求

To send form data to the Form Handler you need to URI encode the field names and values.要将表单数据发送到表单处理程序,您需要对字段名称和值进行 URI 编码。

(Example using JQuery. The '?callback=' is added by ajax() when specifying the dataType: 'jsonp'): (使用 JQuery 的示例。指定 dataType 时,ajax() 添加了 '?callback=' :'jsonp'):

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) {...}

Redirect Pardot From Handler success/error to your own server将 Pardot 从处理程序成功/错误重定向到您自己的服务器

See @nickjag's answer:见@nickjag 的回答:

Set the Success Location and Error Location to endpoints on your backend.将 Success Location 和 Error Location 设置为后端的端点。

As pardot will not forward any of the GET parameters you passed in you'll have to use some defaults on ie the callback function name (hence specifying jsonpCallback and not having a success in my request).由于 pardot 不会转发您传入的任何 GET 参数,因此您必须在 ie 回调函数名称上使用一些默认值(因此指定 jsonpCallback 并且在我的请求中没有成功)。

Return JSONP from your server从您的服务器返回 JSONP

I was having problems with console errors ( Uncaught SyntaxError: Unexpected token : ) when using: return "{ 'result' : 'success' }" as it is a JSON-object and JSONP expects a file with JavaScript.我在使用时遇到控制台错误( Uncaught SyntaxError: Unexpected token :问题: return "{ 'result' : 'success' }"因为它是一个 JSON 对象并且 JSONP 需要一个带有 JavaScript 的文件。 So the format to return should be: return "callback({ 'result' : 'success' })"所以返回的格式应该是: return "callback({ 'result' : 'success' })"

And as again Pardot don't forward the GET params, the generated callback function name from JQuery didn't propagate and I couldn't return the correct JavaScript code.再次 Pardot 不转发 GET 参数,从 JQuery 生成的回调函数名称没有传播,我无法返回正确的 JavaScript 代码。 Defaulted to use the function name "callback" if none was provided.如果没有提供,默认使用函数名称“回调”。

Guide for returning JSONP from .NET MVC backend 从 .NET MVC 后端返回 JSONP 的指南

What Pardot is suggesting is to create 2 static URLs on your own server that return a simple JSON response. Pardot 的建议是在您自己的服务器上创建 2 个返回简单 JSON 响应的静态 URL。

So for example:例如:

  1. mysite.com/pardot-success

Returns: {"result":"success"}返回: {"result":"success"}

  1. mysite.com/pardot-error

Returns: {"result":"error"}返回: {"result":"error"}

You'll then use those two URLs as your success and error redirect URLs for your Pardot form handler settings.然后,您将使用这两个 URL 作为 Pardot 表单处理程序设置的成功和错误重定向 URL。

An AJAX request can then be made to your Pardot form handler using JSONP, which will wrap and return the JSON response from one of those URLs (depending on the result).然后可以使用 JSONP 向您的 Pardot 表单处理程序发出 AJAX 请求,它将包装并返回来自这些 URL 之一的 JSON 响应(取决于结果)。

Your AJAX response data would include your JSON result (success or error).您的 AJAX 响应数据将包括您的 JSON 结果(成功或错误)。

All the answers here really helped me get going on this solution, but my requirement was to get everything working only through Salesforce.此处的所有答案确实帮助我开始使用此解决方案,但我的要求是仅通过 Salesforce 才能使一切正常。 So for anybody looking for the answer using only Salesforce's backend architecture, I hope this helps.因此,对于仅使用 Salesforce 的后端架构寻找答案的任何人,我希望这会有所帮助。 I had to structure my Ajax call a little differently to get it working:我必须以稍微不同的方式构建我的 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);
}

My server, which is built in Apex (Salesforce's programming language) looks like this:我的服务器使用 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" })'));
    }
}

I then expose this REST webservice through a Salesforce SITE, at a URL like:然后,我通过 Salesforce 站点在如下 URL 上公开此 REST web 服务:

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

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

And in the Pardot Form Handler UI, set the Success Location and Error Location fields to these URLs respectively.并在 Pardot 表单处理程序 UI 中,将 Success Location 和 Error Location 字段分别设置为这些 URL。

This is very similar to the other answers for this question, but taken from an entirely Salesforce approach.这与此问题的其他答案非常相似,但完全取自 Salesforce 方法。 It might be somewhat unrelated the the OPs tech-stack, but it should be helpful for people looking for answers in the future.它可能与 OP 技术堆栈有些无关,但它应该对将来寻找答案的人们有所帮助。

Thank you to all the answers on here, after a day of head scratching I managed to work out how to get this working with vanilla js (using vue).感谢您在这里的所有答案,经过一天的摸索之后,我设法弄清楚了如何使用 vanilla js(使用 vue)来实现这一点。 I thought I'd post here to help avoids any poor soul going through the same frustration.我想我会在这里发帖帮助避免任何可怜的灵魂经历同样的挫折。

Success/Error js files to be on the same domain成功/错误 js 文件位于同一域中

success.js:成功.js:

logResult({ result: 'success' });

error.js:错误.js:

logResult({ result: 'error' });

Add these URLs to the "Success Location" and "Error Location" fields in the Pardot Form Handler将这些 URL 添加到 Pardot 表单处理程序中的“成功位置”和“错误位置”字段

Jsonp function Jsonp function

I used vue to build this site so I added the below function to /asses/js/util.js我使用 vue 来构建这个站点,所以我将以下 function 添加到 /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;

Note: the callback function name (logResult) needs to be the same function name that is in your success/error js files注意:回调 function 名称(logResult)需要与成功/错误 js 文件中的 function 名称相同

Submit function提交 function

Script in my vue component (should be easily transferrable to vanilla js/other frameworks):我的 vue 组件中的脚本(应该很容易转移到 vanilla 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM