Search code examples
reactjsherokustripe-payments

Cannot redirect to a success page after submitting payment information on Stripe. Works LOCALLY but not on HEROKU. ("Cannot GET /success")


I am trying to generate a success page after submitting payment information on Stripe but it doesn't work when deployed on Heroku. Locally everything works fine and I am redirected to a success page.

After submitting payment information it just redirects to a page saying "Cannot GET /success".

I am using the MERN stack.

I am using a test key that anyone can obtain from stripes documentation so there is no need to hide it in an ENV file.

Here are the Heroku logs:

at=info method=GET path="/success? 
session_id=cs_test_a1d94XAhzPyyubwBg7Lk3FXKmpViqUYK6UGzcqON3HAdD5ELFUINJyOVsX" 
host=thawing-headland-75590.herokuapp.com request_id=7aff0f42-cd34-4d12-b5b3- 
858ff60e16de fwd="174.112.119.39" dyno=web.1 connect=0ms service=1ms status=404 
bytes=390 protocol=https.

Here is what shows in the console:

constants.override.js:1 
 GET https://thawing-headland-75590.herokuapp.com/success?session_id=cs_test_a1jXbh7ZPggtKlX0840DpYCfTZXr5uZp5soNzvQoCfGRVBVEpmtzfR9lPj 404 (Not Found)
a.handleSuccess @   constants.override.js:1
a   @   js.stripe.com/v3/fin…36134c4204a1d0.js:1
setTimeout (async)      
(anonymous) @   js.stripe.com/v3/fin…36134c4204a1d0.js:1
value   @   constants.override.js:1
Lr  @   content.js:1
t.unstable_runWithPriority  @   content.js:1
Ot  @   content.js:1
jr  @   content.js:1
Sr  @   content.js:1
(anonymous) @   content.js:1
t.unstable_runWithPriority  @   content.js:1
Ot  @   content.js:1
At  @   content.js:1
Nt  @   content.js:1
_r  @   content.js:1
notify  @   content.js:1
notifyNestedSubs    @   content.js:1
n   @   content.js:1
l   @   content.js:1
(anonymous) @   constants.override.js:1
(anonymous) @   content.js:1
dispatch    @   content.js:1
(anonymous) @   constants.override.js:1.

Here is my server.js

        const express = require("express");
        const { ApolloServer } = require("apollo-server-express");
        const path = require("path");

        const { typeDefs, resolvers } = require("./schemas");
        const { authMiddleware } = require("./utils/auth");
        const db = require("./config/connection");

        const PORT = process.env.PORT || 3001;
        const app = express();
        const server = new ApolloServer({
          typeDefs,
          resolvers,
          context: authMiddleware
        });

        app.use(express.urlencoded({ extended: false }));
        app.use(express.json());

     
        app.use("/images", express.static(path.join(__dirname, "../client/images")));

        if (process.env.NODE_ENV === "production") {
          app.use(express.static(path.join(__dirname, "../client/build")));
        }

        app.get("/", (req, res) => {
          res.sendFile(path.join(__dirname, "../client/build/index.html"));
        });

      
        const startApolloServer = async (typeDefs, resolvers) => {
          await server.start();
          server.applyMiddleware({ app });

          db.once("open", () => {
            app.listen(PORT, () => {
              console.log(`API server running on port ${PORT}!`);
              console.log(`Use GraphQL at http://localhost:${PORT}${server.graphqlPath}`);
            })
          })
          };

          startApolloServer(typeDefs, resolvers);

Here is my resolver.js

        const { AuthenticationError } = require("apollo-server-express");
        const { User, Product, Console, Order } = require("../models");
        const { signToken } = require("../utils/auth");
        const stripe = require("stripe")("sk_test_123");

        const resolvers = {
          Query: {
            consoles: async () => {
              return await Console.find();
            },
            products: async (parent, { console, name }) => {
              const params = {};

              if (console) {
                params.console = console;
              }

              if (name) {
                params.name = {
                  $regex: name
                };
              }

              return await Product.find(params).populate("console");
            },
            product: async (parent, { _id }) => {
              return await Product.findById(_id).populate("console");
            },
            user: async (parent, args, context) => {
              if (context.user) {
                const user = await User.findById(context.user._id).populate({
                  path: "orders.products",
                  populate: "console"
                });

                user.orders.sort((a, b) => b.purchaseDate - a.purchaseDate);

                return user;
              }

              throw new AuthenticationError("Not logged in");
            },
            order: async (parent, { _id }, context) => {
              if (context.user) {
                const user = await User.findById(context.user._id).populate({
                  path: "orders.products",
                  populate: "console"
                });

                return user.orders.id(_id);
              }

              throw new AuthenticationError("Not logged in");
            }, 
            checkout: async (parent, args, context) => {
              const url = new URL(context.headers.referer).origin;
              const order = new Order({ products: args.products });
              const line_items = [];
              const { products } = await order.populate("products");


              for (let i = 0; i < products.length; i++) {
            
                const product = await stripe.products.create({
                  name: products[i].name, 
                  description: products[i].description,
                  images: [`${url}/images/${products[i].image}`]
                });

                const price = await stripe.prices.create({
                  product: product.id, 
                  unit_amount: products[i].price * 100, 
                  currency: "usd", 
                });

              
                line_items.push({
                  price: price.id, 
                  quantity: 1
                });
              }

              const session = await stripe.checkout.sessions.create({
                payment_method_types: ["card"], 
                line_items, 
                mode: "payment", 
                success_url: `${url}/success?session_id={CHECKOUT_SESSION_ID}`,
                cancel_url: `${url}/`
              });
              return { session: session.id };
            }

Like I said before, everything works fine locally so I am kind of stuck as to why it won't work on Heroku. Every other part of this website works fine on Heroku. It is just going from PAYMENT to SUCCESS where there is a problem.

Thanks in advance!


Solution

  • It works now. After many hours of looking in the wrong direction all I needed to do was add the following in my server.js file:

    app.get("/success", (req, res) => {
      res.sendFile(path.join(__dirname, "../client/build/index.html"));
    });