javascript - url 将 php 数据编码为 json 对象
问题描述
请阅读 - 这不仅仅是简单地将 json_encode 从 php 转换为 javascript。
我们的计费系统使用 Authorize.net。使用 Authorize.net API,我们在 PHP 中创建一个令牌请求。请求中的数据传递客户信息、余额、帐单地址等——这些数据直接使用 PHP 发送。作为响应,我们得到一个要在 PHP 中处理的令牌 - 然后将该令牌嵌入到 HTML 表单输入中。
信用卡表单提交后,我们得到一个 javascript json 响应返回到表单以供其他 JS 函数处理。一切正常,直到我们有一个客户&
在他们的公司名称中(IE Bar & Grill
:)
仅在返回表单的&
json 响应中触发错误 - 特别是我们得到的错误是:unexpected end of json input
这会导致其余脚本出错。
那么,问题是,PHP 令牌请求中的客户数据是否需要进行 urlencoded - 或者是否有特殊的方法来处理 json 响应?据我所知,Authorize 只是在 json 响应中返回确切的客户数据 - 所以如果我们在前端对其进行 url 编码(在发送令牌请求之前),那么这是否意味着我们还需要对 json 响应进行 url 解码.
它的一种鸡和一个鸡蛋是第一个问题。
Authorize.net 令牌请求(在 PHP 中):
$customerData = new AnetAPI\CustomerDataType();
$customerData->setType("business");
$customerData->setId($ss['authCustID']);
$customerData->setEmail($ii['cEmail']);
// Set the Bill To info for new payment type
$billTo = new AnetAPI\CustomerAddressType();
$billTo->setFirstName($ii['cFirstName']);
$billTo->setLastName($ii['cLastName']);
$billTo->setCompany($ii['cName']); // #1 <----- IE: "Bar & Grill"
$billTo->setAddress($ii['cAddress']. " " .$ii['cAddress1']);
$billTo->setCity($ii['cCity']);
$billTo->setState($ii['cState']);
$billTo->setZip($ii['cZip']);
$billTo->setCountry("USA");
// set shipping profile
$shipTo = clone $billTo ;
// extend billTop profile
$billTo->setFaxNumber('8005551212') ;
$billTo->setPhoneNumber($ii['cPhone']);
//create a transaction
$transactionRequestType = new AnetAPI\TransactionRequestType();
$transactionRequestType->setTransactionType("authCaptureTransaction");
$transactionRequestType->setAmount($ss['balance']);
$transactionRequestType->setCustomer($customerData) ;
$transactionRequestType->setOrder($order) ;
$transactionRequestType->setBillTo($billTo) ;
$transactionRequestType->setShipTo($shipTo) ;
// Build transaction request
$request = new AnetAPI\GetHostedPaymentPageRequest();
$request->setMerchantAuthentication($merchantAuthentication);
$request->setRefId($refId);
$request->setTransactionRequest($transactionRequestType);
//execute request
$controller = new AnetController\GetHostedPaymentPageController($request);
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::PRODUCTION); // SANDBOX or PRODUCTION
$gToken=[] ;
if (($response != null) && ($response->getMessages()->getResultCode() == "Ok")) {
//echo $response->getToken()."\n";
$gToken["Error"] = 0 ;
$gToken["Token"] = $response->getToken() ;
} else {
//echo "ERROR : Failed to get hosted payment page token\n";
$errorMessages = $response->getMessages()->getMessage();
//echo "RESPONSE : " . $errorMessages[0]->getCode() . " " .$errorMessages[0]->getText() . "\n";
$gToken["Error"] = 1 ;
$gToken["errMsg"] = $errorMessages[0]->getCode() . ": " .$errorMessages[0]->getText() ;
}
表单/JSON 响应处理程序:
AuthorizeNetPopup.onReceiveCommunication = function (querystr) {
var params = parseQueryString(querystr);
//console.log(params) ;
switch (params["action"]) {
case "successfulSave":
AuthorizeNetPopup.closePopup();
break;
case "cancel":
AuthorizeNetPopup.closePopup();
break;
case "transactResponse":
// 'response' is a string value
// encode it as an object, to be passed to global function
// that will decode it again for PHP
console.log(params["response"]) ;
var response = JSON.parse(params["response"]); // #2 <--- ERROR: unexpected end of json input
//var response = params["response"];
httpReceipt(response) ;
AuthorizeNetPopup.closePopup();
break;
case "resizeWindow":
var w = parseInt(params["width"]);
var h = parseInt(params["height"]);
var ifrm = document.getElementById("iframeAuthorizeNet");
ifrm.style.width = w.toString() + "px";
ifrm.style.height = h.toString() + "px";
centerPopup();
break;
}
};
我是在#1(在php部分)对数据进行url编码还是在处理json响应之前(在#2)对json响应进行url编码-或两者兼而有之?非常困惑如何处理这个问题。我们是否需要对添加到令牌请求的每个参数的数据进行编码 - 或者我们可以在提交之前对整个请求进行编码吗?无论通信的哪一端应用编码/解码,正确的编码/解码调用是什么?
更新
为了说明流程:
- paymentPage.html -> PHP 生成token,将token嵌入到页面表单中,还有iframe
paymentPageFrame.html
- paymentPageFrame.html -> iFrame 通信器页面,在 paymentPage.html 和 authorize.net 之间中继消息
- paymentPage.html ->
onReceiveCommunication
用于处理来自 paymentPageFrame.html 的消息的javascript
事实证明,authorize.net 正在将 URL 字符串返回到 paymentPageFrame.html - 该字符串未进行 urlencoded。然后将字符串传递回父onReceiveCommunication
级,此时使用自定义解析器对其进行解析:
function parseQueryString(str) {
var vars = [];
var arr = str.split('&');
var pair;
for (var i = 0; i < arr.length; i++) {
pair = arr[i].split('=');
vars.push(pair[0]);
vars[pair[0]] = unescape(pair[1]);
}
return vars;
}
然后,此自定义解析器导致其中包含的数据值&
(即:“company”:“Bar & Grill”)将名称分成两半,最终导致 json 输入的无效/意外结束。
string
被传递回 iFrame,而 iFrame 又被传递给父级的是:
action=transactResponse&response={"accountType":"Visa","accountNumber":"XXXX0623","transId":"62830720474","responseCode":"1","authorization":"185778","shipTo":{"firstName":"Bob","lastName":"Jones","company":"Backyard Bar & Grill","address":"123 Main St ","city":"Tampa","state":"FL","zip":"33606","country":"USA"},"orderDescription":"2020-12-01 bill for All Regions/All Sites","customerId":"1002-0","totalAmount":"1.50","orderInvoiceNumber":"11386-0","dateTime":"2/2/2021 4:57:53 PM","refId":"ref1612285039"}
现在字符串位于父页面中,我正在尝试找出对其进行编码然后解析它的最佳方法,这样当其中包含数据值时它不会在解析时中断&
(IE Backyard Bar & Grill
:)
到目前为止,我正在尝试,但没有成功:
var urlstr = encodeURIComponent(response) ; // encode it first
var newUrl = new URLSearchParams(urlstr) ; // then proper parse it
但是当我尝试访问参数时,它返回 null:
consoole.log(newUrl.get('action')) ;
> null
解决方案
经过多次修补,我终于编写了自己的解析器:
A:如果存在,先捕获响应JSON
B:然后解析其余的 URL 参数:
C:将所有参数和响应对象作为单个对象返回
var str = 'action=transactResponse&response={"accountType":"Visa","accountNumber":"XXXX0623","transId":"62830720474","responseCode":"1","authorization":"185778","shipTo":{"firstName":"Preston","lastName":"Rolinger","company":"Backyard & Grill","address":"2808 W Foster Ave S ","city":"Tampa","state":"FL","zip":"33611","country":"USA"},"orderDescription":"2020-12-01 bill for All Regions/All Sites","customerId":"1002-0","totalAmount":"1.50","orderInvoiceNumber":"11386-0","dateTime":"2/2/2021 4:57:53 PM","refId":"ref1612285039"}&moreKey="other value"' ;
function parseResponse(str) {
var resInfo = [], res = {} ;
if (str.match("&response=")) {
var params = str.split("&response=") ; // leading params & response obj
if (params[1].match("}&")) {
resInfo = params[1].split("}&") ; // splits off anything at end of obj
res.response = JSON.parse(resInfo[0] + "}") ; // add } to complete obj string again
} else {
res.response = JSON.parse(params[1]) ; // else it already is the json string
}
if (resInfo[1]) {
params = params[0]+ "&" +resInfo[1] ; // join url params back together
} else {
params = params[0] ;
}
} else {
params = str ; // else the str has no "response" in it, process just params
}
params = new URLSearchParams(encodeURI(params)) ; //encode then parse
params.forEach(function(value, key) {
res[key] = value ;
}) ;
return res ;
}
var response = parseResponse(str) ;
console.log(response) ;
推荐阅读
- python - Python:如何使用 3 个数组 x[]、y[]、z[] 在 3D 中应用 polyfit 功能
- dart - 如何对内部和外部地图进行排序?
- ionic-framework - 离子原生推送通知(Firebase X)不显示应用程序是否在后台
- c++ - 是否可以仅取消隐藏基类的特定重载方法
- javascript - Modify the file before it opens and then open it in a new tab
- django - Target WSGI scriptcannot be loaded as Python module
- python - How to install project in git repository correctly in python?
- python - 如何在 Git repo 中处理应用程序密码
- jboss - ORA-12519 TNS: No appropriate service handler found in JBoss 7.2
- c++ - C++ logical negated comparison operator doesn't work