0

I'm trying to build a custom payment flow using Stripe. It's working locally, but when I try to put it online, I get an error after a certain time. I asked my web hosting service if they put any filter, but apparently not. You'll find the code bellow. For the Javascript, I basically copy pasted the code given by Stripe. Also, I don't get any payment intent on the Stripe end, so I think my web app can't connect to Stripe. Visually the form where the user is supposed to enter his card number etc isn't appearing.

The error I get after a certain time on the payment intent page error image

The server side code (C#):

[Authorize]
[Route("/create-payment-intent")]
[ApiController]
public class PaymentIntentApiController : Controller
{
    private readonly UserManager<AppUser> userManager;
    private readonly ApplicationDbContext db;

    public PaymentIntentApiController(UserManager<AppUser> userManager, ApplicationDbContext db)
    {
        this.userManager = userManager;
        this.db = db;
    }

    [HttpPost]
    public async Task<ActionResult> Create(ProductViewModel request)
    {
        if (request == null)
        {
            return RedirectToAction("Checkout", "Payment");
        }

        ComplexDbOperations cdo = new ComplexDbOperations(db);
        Data.Objects.Product product = new Data.Objects.Product { period = request.period, sub = request.subscription };

        int price = ProductViewModel.calculateStripePrice(await cdo.getPricesAsync(product.ToRole().ToString()));
        if (price <= 0)
        {
            return RedirectToAction("Checkout", "Payment");
        }

        AppUser user = await userManager.GetUserAsync(User);
        if (user == null) return RedirectToAction("Index", "Home");

        var paymentIntents = new PaymentIntentService();

        var paymentIntentOptions = new PaymentIntentCreateOptions
        {
            Amount = price,
            Currency = "chf",
            Description = string.Format("Abonnement {0} pour {1}, Periode : {2}", request.subscription.ToString(), user.Email, request.period.ToString()),
            Metadata = new Dictionary<string, string>
              {
                {"Abonnement", request.subscription.ToString()},
                {"Periode", request.period.ToString() },
                {"UserId", user.Id },
                {"UserEmail", user.Email },
                {"subCode", ((int)request.subscription).ToString()},
                {"periodCode", ((int)request.period).ToString() },
              }
        };

        var paymentIntent = paymentIntents.Create(paymentIntentOptions);
        return Json(new { clientSecret = paymentIntent.ClientSecret });
    }
}

    

What I've modified from Stripe on the client side code (js) :

// The items the customer wants to buy
var purchase = {
    period: parseInt(document.getElementById("period").value),
    subscription: parseInt(document.getElementById("subscription").value)
};

// Disable the button until we have Stripe set up on the page
document.querySelector("button").disabled = true;
fetch("/create-payment-intent", {
    method: "POST",
    headers: {
        "Content-Type": "application/json"
    },
    body: JSON.stringify(purchase)
})... (stripe code continuing)

Can you please help me ? I don't even know how I can get more details on the error as I can't debug the program when it's online.

Thanks in advance.

[Update] I logged the server error and got :

System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (api.stripe.com:443)
Omar Shawky
  • 1,242
  • 1
  • 12
  • 25
S. Delsad
  • 23
  • 4
  • Error 502 is a gateway error (so your gateway front door -typically a reverse proxy or load balancer- either couldn't contact or timed out trying to reach your server, so it sounds like an infrastructure problem, rather than a programming problem (specially if your code works locally). Not sure there's any help we can give you here – Jcl Sep 13 '21 at 09:46
  • Ok, thank you for your answer. So do you think the problem comes from my web hosting service ? – S. Delsad Sep 13 '21 at 09:55
  • I have no clue. It could be a timeout problem... for example, if your site is hosted in Azure (example only), they have a load balancer in place which times out at 230 seconds. If your web app takes more than 230 seconds to respond, end-users will get a 502 (however your application will still work and end the request). But it could be a myriad of other things, not necessarily related to your programming. – Jcl Sep 13 '21 at 10:31
  • Also read https://support.stripe.com/questions/how-to-fix-syntaxerror-unexpected-token-in-json-at-position-0 . The short answer is — check your server logs. – karllekko Sep 13 '21 at 11:25
  • Thanks for your answers. So I logged the error and got : "System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (api.stripe.com:443)" Does anyone have already dealt with smg like this ? – S. Delsad Sep 14 '21 at 14:25
  • Thanks for a really clear answer. The code really needs to be in-line, it's not enough to put the proxy server details in your web.config file. Saved me hours with Stripe support ! – jon morgan Feb 16 '23 at 11:59

1 Answers1

0

I finally know what was the problem so I'll explain what it was and how to solve it if someone encounters the same error.

The first thing I did was, as suggested by karllekko, to check the server logs when it was running on the hosted service. For that, I used Serilog which is a package that allows you to store the logs into a file (It was the simpliest solution for me). I then got a more precise error :

HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time...

From this error, I knew I wasn't able to get to stripe's servers. I found a simple ping function in C# that checks if my assumption was right and it was.

I then checked with my host service provider how I could access an external IP: they use a proxy server for security reasons.

I added this code before creating the payment intent which uses the proxy server :

var handler = new HttpClientHandler
{
    Proxy = new WebProxy(proxyServer),
    UseProxy = true,
};
var httpClient = new HttpClient(handler);

var stripeClient = new StripeClient(
    apiKey: secretApiKey,
    httpClient: new SystemNetHttpClient(httpClient)
);
StripeConfiguration.StripeClient = stripeClient;

I hope if someone encounters the same error he will be able to solve the problem with this answer.

S. Delsad
  • 23
  • 4