NextJs 14 App Router SSR route.ts 中没有用于 Amplify GraphQL 的凭据 + 无 Cookies

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

我正在设置一个route.ts来处理Stripe webhook。我需要在成功通过 Amplify / AppSync 更新 dynamodb 后发出 graphql 请求。

这是使用新的 NextJs 14 应用程序路由器。 SSR 似乎在 Amplify 中有很好的记录。

我总是在 createTransaction graphql 请求中收到错误“No Credentials”。我传递给 nextServerContext 的 cookie 总是空的 - 看起来这就是问题所在。

我在本地运行。

我已经尝试过:

  • 这个在layout.tsx中

Amplify.configure(amplifyConfig, {
  ssr: true // required when using Amplify with Next.js - it make Amplify store the auth tokens in cookies
});

还尝试将节点升级到20.11.0 尝试使用 reqResBasedClient 和 runWithAmplifyServerContext

// This doesn't work because "req" is from NextRequest not the old NextApiRequest 
        const result = await runWithAmplifyServerContext({
           nextServerContext: { req },
           operation: async (contextSpec) => {
             const request = await reqResBasedClient.graphql(contextSpec, {
               query: createTransaction,
                     variables: {
                       transaction: transactionInput
                     },
             });
    
             return request.data.createTransaction.paymentIntentId;
           }
         });

非常感谢任何帮助!有人如何将 Amplify 与 App Router 结合使用?我有一种感觉 Amplify 应该使用当前的身份验证凭据更新 cookie,但 route.ts 中的 cookie 都是空/空。

import { NextRequest, NextResponse } from "next/server";
import Stripe from 'stripe';
import { createTransaction } from '../../../graphql/mutations';
import { TransactionInput } from '../../../graphql/API';

import { cookieBasedClient } from '../../../utils/amplifyServerUtils';
import { cookies } from 'next/headers'; // this is supposed to be for ssr but it's always null 


const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  // @ts-ignore
  apiVersion: '2022-11-15',
});

export async function POST(req: NextRequest) {
  if (req.method !== 'POST') {
    return new NextResponse(JSON.stringify({ error: 'Method not allowed' }), {
      status: 405,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }

  // Cookie debug
  const rawCookies = req.headers.get('cookie');
  console.log('Raw Cookie String:', rawCookies);

  const otherRawCookies = req.cookies.getAll();
  console.log('Other Raw Cookies:', otherRawCookies);

  console.log('cookies from next header = ', cookies().getAll());


  const sig = req.headers.get('stripe-signature');
  let event;

  try {
    const body = await readRawBody(req);
    event = stripe.webhooks.constructEvent(body, sig!, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch (err: any) {
    return new NextResponse(JSON.stringify({ error: `Webhook Error: ${err.message}` }), {
      status: 400,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  }

  switch (event.type) {
    case 'charge.succeeded':
      console.log('Handling charge.succeeded');
      break;
    case 'payment_intent.created':
      console.log('Handling payment_intent.created');
      break;
    case 'payment_intent.canceled':
      console.log('Handling payment_intent.canceled');
      break;
    case 'payment_intent.succeeded':
      console.log('Handling payment_intent.succeeded');

      const paymentIntentSucceeded = event.data.object as Stripe.PaymentIntent;

      console.log('paymentIntentSucceeded = ', paymentIntentSucceeded);

      const transactionInput: TransactionInput = {
        transactionId: paymentIntentSucceeded.id,
        userId: '1234', // TODO: get this
        amount: paymentIntentSucceeded.amount, 
        currency: paymentIntentSucceeded.currency,
        timestamp: new Date().toISOString(),
        status: paymentIntentSucceeded.status, 
        paymentIntentId: paymentIntentSucceeded.id, 
        priceId: 'priceId', // TODO: set this 
      };
      
      try {
        // This doesn't work. Fails with "No Credentials" error 
        const result = await cookieBasedClient.graphql({
          query: createTransaction,
                    variables: {
                      transaction: transactionInput
                    },
        })


        console.log("createTransaction result transactionId = ", result.data.createTransaction?.transactionId);

    } catch (error) {
        console.log("createTransaction failed with error: ", error);
    }
      break;
    default:
      console.log('Unhandled Stripe webhook event type:', event.type);
      break;
  }

  return new NextResponse(JSON.stringify({ received: true }), {
    status: 200,
    headers: {
      'Content-Type': 'application/json',
    },
  });
}

// Helper function to read raw request body
async function readRawBody(req: NextRequest): Promise<string> {
  if (!req.body) {
    throw new Error("Request body is null");
  }

  const reader = req.body.getReader();
  let receivedValue = '';
  let done = false;

  while (!done) {
    const { value, done: readerDone } = await reader.read();
    done = readerDone;
    if (value) {
      receivedValue += new TextDecoder().decode(value, { stream: true });
    }
  }

  return receivedValue;
}

next.js graphql stripe-payments aws-amplify
1个回答
0
投票

问题

aws-amplify/amplify-js #12867
现在有结论:

我们有一个标记版本,您可以使用它来测试它是否可以解决您的问题。请注意,这些并不用于生产,仅用于验证。

在您的项目中安装这些软件包和版本,并让我们知道它是否可以解决您的问题。

npm i [email protected] @aws-amplify/[email protected]
iam-auth-server.ebba1a4.0

它似乎有效:

const client = generateServerClientUsingCookies({
  config: config,
  cookies,
  // authMode: "iam", Default is configured to IAM
});

const mutationTest = await client.graphql({
  query: mutations.createTodo,
  variables: {
    input: {
      content: "Content",
    },
  },
  // authMode: "iam", Default is configured to IAM
});

const queryTest = await client.graphql({
    query: queries.listTodo,
    variables: {},
    // authMode: "iam", Default is configured to IAM
  });
© www.soinside.com 2019 - 2024. All rights reserved.