如何让部署在 Google Cloud Run 上的 Node.js 应用程序调用 Square API?

问题描述 投票:0回答:1

以下是我在尝试使用 Square API 创建客户时在浏览器中遇到的两个错误:

  1. 超时(504网关超时): 对 https://backend-437525971388.us-central1.run.app/customer 的 POST 请求失败,并出现 504 网关超时错误。

  2. CORS 错误: 从源“https://buzzysweets.com”获取“https://backend-437525971388.us-central1.run.app/customer”的访问已被 CORS 策略阻止:无“Access-Control-Allow-Origin” ' 请求的资源上存在标头。

我使用控制台日志验证了正在使用正确的生产应用程序 ID、位置 ID、访问令牌和 CDN。

请注意:在我的开发环境中,我使用沙箱凭证和 cdn 成功创建了客户、订单和付款。我还使用生产凭证和 CDN 成功创建了客户和订单。

总而言之,我无法从托管于 https://buzzysweets.com 的前端向托管于 Google Cloud Run https://backend-437525971388.us-central1.run 的后端 API 发出 POST 请求。应用程序/客户。以下是代码片段:

import React, { useEffect, useState } from 'react';
text`import { selectCart } from '../../features/cart/cartSlice';
import { useSelector } from 'react-redux';

const PaymentForm = () => {
  const appId = process.env.REACT_APP_YOUR_SQUARE_APPLICATION_ID;
  const locationId = process.env.REACT_APP_YOUR_SQUARE_LOCATION_ID;

  const { customerInfo } = useSelector(selectCart);

  // Load Square Web Payments SDK
  useEffect(() => {
    const loadSquare = async () => {
      if (!window.Square) {
        return;
      }

      const payments = window.Square.payments(appId, locationId);

      try {
        const card = await payments.card();
        await card.attach('#card-container');
        setCard(card);
      } catch (err) {
        console.error('Error loading Square SDK', err);
      }
    };

    loadSquare();
  }, []);

  const handlePayment = async (e) => {
    e.preventDefault();
    if (!card) return;

    try {
      const tokenResult = await card.tokenize();
      if (tokenResult.status === 'OK') {
        const customerResults = await createCustomer(tokenResult.token, customerInfo);
      }
    } catch (err) {
      console.error('Payment error:', err);
    }
  };

  const createCustomer = async (token, customerInfo) => {
    const bodyParameters = {
      address: {
        address: customerInfo.address,
        country: customerInfo.country,
        firstName: customerInfo.firstName,
        lastName: customerInfo.lastName,
        zipCode: customerInfo.zipcode,
      },
      givenName: customerInfo.firstName,
      familyName: customerInfo.lastName,
      emailAddress: customerInfo.emailAddress,
      idempotency_key: window.crypto.randomUUID(),
    };

    const body = JSON.stringify(bodyParameters);
    
    try {
      const response = await fetch(`${process.env.REACT_APP_API_URL_BACK}/customer`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${token}`,
        },
        body,
      });

      const result = await response.json();

      if (!response.ok) {
        throw new Error(`Failed to create customer: ${result.errors[0].detail}`);
      }

      return result;
    } catch (err) {
      console.error('Error creating customer:', err);
    }
  }; 
};


//ON MY BACKEND SIDE: USING NODE.JS
// server.js
const { ApiError, client: square } = require('./server/square');
const corsMiddleware = require('micro-cors')({
  origin: process.env.REACT_APP_API_URL_FRONT,
  allowMethods: ['POST', 'GET'],
  allowedHeaders: ['Content-Type', 'Authorization'],
});

async function createCustomer(req, res) {
  const payload = await json(req);

  await retry(async (bail, attempt) => {
    try {
      const customerReq = {
        address: {
          addressLine1: payload.address.address,
          firstName: payload.address.firstName,
          lastName: payload.address.lastName,
          country: payload.address.country,
          postalCode: payload.address.zipCode,
        },
        emailAddress: payload.emailAddress,
        idempotencyKey: payload.idempotency_key,
        familyName: payload.familyName,
      };

       console.log('customerReq:', customerReq) //This output shows correctly in Google Cloud Run's logs
     const { result, statusCode } = await square.customersApi.createCustomer(customerReq);
      console.log('customer returned result:', result); //Google Cloud Run does not show any output from this console.log
      
send(res, statusCode, {
        success: true,
        customer: {
          id: result.customer.id,
          status: result.customer.status,
        },
      });
    } catch (ex) {
      if (ex instanceof ApiError) {
        logger.error("API Error:", ex.errors);
        bail(ex);
      } else {
        logger.error(`Unexpected error: ${ex}`);
        throw ex;
      }
    }
  });
}

const appRouter = router(post('/customer', createCustomer));
const corsWrappedApp = corsMiddleware(appRouter);

if (require.main === module) {
  const PORT = process.env.PORT || 8080;
  require('http')
    .createServer(corsWrappedApp)
    .listen(PORT);
}

module.exports = corsWrappedApp;

//config.js file: create Square API client
require('dotenv').config({
  path: process.env.NODE_ENV === 'production' ? '.env.production' : '.env.sandbox', // Dynamically choose .env file based on NODE_ENV
});

const { Client, Environment } = require('square');

const client = new Client({
  environment: process.env.NODE_ENV === 'production' ? Environment.Production : Environment.Sandbox,
  accessToken: process.env.SQUARE_ACCESS_TOKEN, 
});

module.exports = {
  client,
  isProduction: process.env.NODE_ENV === 'production',
};

//square.js file: 
// Import the client from the config file
const { client } = require('./config');
const { ApiError } = require('square');

(async () => {
  try {
    const { result, statusCode } = await client.customersApi.listCustomers();
    console.log('Customers retrieved successfully:', result.customers);
  } catch (ex) {
    // Handle errors
    if (ex instanceof ApiError) {
      console.error('API Error:', ex.errors);
    } else {
       console.error('Unexpected Error:', ex);
    }
  }
})();

module.exports = { ApiError: client.ApiError, client };

http cors google-cloud-run square http-status-code-504
1个回答
0
投票

CORS(跨源资源共享)似乎未正确设置,或者您的 Cloud Run 无法处理 POST 方法。

从这篇post中找到约翰·汉利(John Hanley)的答案,可能对您有帮助:

注意您的 POST 上的 HTTP 302 响应。这意味着客户被指示去一个新位置。然后,您的客户端将 POST 转换为 GET 并在新位置发出另一个请求。

Cloud Run 仅支持 HTTPS。您的 POST 请求正在发送到 HTTP 端点。 Cloud Run 前端会自动将客户端重定向到 HTTPS 端点。

将您的请求从使用 HTTP 更改为 HTTPS。

您还可以查看有关 处理 COR (一种让在一个域上运行的应用程序访问另一个域的方法)和 CORS 限制的文档,因为您遇到了 CORS 错误。

© www.soinside.com 2019 - 2024. All rights reserved.