My team spent a few engineering weeks working on this problem and we haven't been able to fix it all-the-way, but we have made some progress and found out some information that I thought would be helpful to share.
Firstly, let me describe some of the things that happen when a user clicks Magento's Place Order button when Direct Post has been selected. (Feel free to skip this section and come back to it later)
- Browser does ajax request to Magento - the "place" request.
- Magento creates a new order and puts order into "Pending Payment" status. The response includes the newly created order number and some other details such as the appropriate authorize.net url where the payment information will be posted to.
- The browser submits a form to the authorize.net url. Request includes CC details and Magento order number.
- Authorize.net servers then send http request to Magento, order number and some other details are included like if payment was successful. Magento changes order status to Confirmed Payment.
- Magento's response back to Authorize.net servers is a very basic html page which essentially has a
window.location=url-to-success-page-here
- Authorize.net servers then relay the HTML in Magento's response back to the browser. This response is loaded in a hidden iframe.
- (More boring details)
- Browser is redirected to success page
Okay even though I included a lot of nitty gritty details, I left a lot out too like error handling, I think that gives the main idea.
What we found is that the problem lies between step 3 and 6. The form that is submitted in step 3 gets loaded into the hidden iframe in step 6. When we added in a bunch of JS logging on our production environment and we found that when the orders failed that iframe was loading VERY quickly - too quickly.
While we haven't found the root cause for this in all cases, we have identified that users that have Kaspersky antivirus will get this problem every time. We were able to replicate on our developer machines as well! Kaspersky AV intercepts the https request because it has "authorize.net" listed in some type of "financial" category. Instead of letting the browser reach out to authorize.net, Kaspersky AV intercepts the request and returns http code "499" as well as some HTML that would be displayed like this:
Well except that remember, the iframe is hidden. So the user can't see it (we did some coding changes to show the iframe and so that is how we got this screenshot). And so the user's experience is that they click "Place Order" and it is disabled/greyed out and then nothing happens ever - like it hangs. But hidden away in that iframe is Kaspersky AV asking the user to open this authorize.net url in a "Protected Browser." LAME! Disabling Kaspersky AV fixes the problem.
But we think it is doubtful that Kaspersky is the only culprit. There could be other AV software, or firewalls, etc that could be doing similar things. Heck it could be some type of DNS problem, or it could be that authorize.net is having some type of outage and they are responding with a 500 or other error code. It could be so many things, and since it is browser-based and browsers have cross-origin restrictions in place we may never figure it out fully.
Our solution:
We coded some changes to the JS (and more)
- We changed the JS to retry the form submit to authorize.net. It tries 4 times. Lots of times it will fail on the first couple tries and succeed on the 3rd or 4th time
- After the 4th try we make the hidden iframe visible, front and center so the user can see what is in there. And we also have a JS alert() that says some mumbo jumbo. Oh and we do some other stuff to put the items back in their cart so they can try again.
We still get some Pending Payment orders, but now most of those customers just try again and it works. Our solution is FAR from perfect, but it is a little better than it was before.
I am definitely interested in seeing if other people have been able to solve (or at least minimize) this problem.