我正在设置一个route.ts来处理Stripe webhook。我需要在成功通过 Amplify / AppSync 更新 dynamodb 后发出 graphql 请求。
这是使用新的 NextJs 14 应用程序路由器。 SSR 似乎在 Amplify 中有很好的记录。
我总是在 createTransaction graphql 请求中收到错误“No Credentials”。我传递给 nextServerContext 的 cookie 总是空的 - 看起来这就是问题所在。
我在本地运行。
我已经尝试过:
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;
}
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
});