You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js+Supabase登录功能405错误及状态反馈实现问题

问题描述

我按照官方文档实现了基于Next.js的登录页面(路径:/app/login/page.tsx)和Supabase认证路由(路径:/app/auth/login/route.ts),但无法添加登录成功提示与错误处理逻辑。参考方案修改代码后,出现错误:POST http://localhost:3000/auth/login net::ERR_ABORTED 405 (Method Not Allowed),以下是修改前后的相关代码,求解决办法。

初始代码

路由文件 /app/auth/login/route.ts

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

export async function POST(request: Request) {
  const requestUrl = new URL(request.url)
  const formData = await request.formData()
  const email = String(formData.get('email'))
  const password = String(formData.get('password'))
  const cookieStore = cookies()
  const supabase = createRouteHandlerClient({ cookies: () => cookieStore })

  await supabase.auth.signInWithPassword({
    email,
    password,
  })

  return NextResponse.redirect(requestUrl.origin, {
    status: 301,
  })
}

登录页面 /app/login/page.tsx

import Link from "next/link";

export default function LoginPage() {
  return (
    <>
      <form action="/auth/login" method="post">
      <label htmlFor="email">Email</label>
      <input name="email" />
      <label htmlFor="password">Password</label>
      <input type="password" name="password" />
      <button>Sign In</button>
    </form>

    <Link href="/reset-password">Reset Password</Link>
    </>
  )
}

修改后代码

路由文件 /app/auth/login/route.ts

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { NextApiRequest, NextApiResponse } from 'next';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const jsonBody = await req.body.json();
  const email = jsonBody.email;
  const password = jsonBody.password;
  const cookieStore = cookies();
  const supabase = createRouteHandlerClient({ cookies: () => cookieStore });

  try {
    const { error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });

    if (error) {
      return res.status(401).json({ message: 'Login failed. Please check your credentials.' });
    }
    return res.status(200).json({ message: 'Login successful' });
  } catch (error) {
    console.error('An error occurred:', error);
    return res.status(500).json({ message: 'An unexpected error occurred' });
  }
}

登录页面 /api/login/page.tsx

'use client'

import { useRouter } from 'next/navigation';
import { useState } from 'react';

export default function LoginPage() {
  const router = useRouter();
  const [error, setError] = useState<string>('');
  const [email, setEmail] = useState<string>('');
  const [password, setPassword] = useState<string>('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
  
    try {
      const response = await fetch('/auth/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email, password }),
      });
  
      if (response.status === 200) {
        router.push('/');
      } else {
        if (response.headers.get('content-type')?.includes('application/json')) {
          const result = await response.json();
          setError(result.message);
        } else {
          setError('An unexpected error occurred.');
        }
      }
    } catch (error) {
      console.log(error, "error on the login page.tsx")
      console.error('An error occurred:', error);
      setError('An unexpected error occurred.');
    }
  };

  return (
    <>
      <form onSubmit={handleSubmit}>
        <label htmlFor="email">Email</label>
        <input
          type="email"
          name="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
        <label htmlFor="password">Password</label>
        <input
          type="password"
          name="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <button type="submit">Sign In</button>
      </form>

      {error && <p>{error}</p>}
    </>
  );
}

解决办法

1. 修复认证路由文件(/app/auth/login/route.ts)

修改后的路由误用了Pages Router的handler写法,而你的项目是App Router结构,必须导出POST方法而非handler,同时使用App Router的Request对象处理请求:

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
import { cookies } from 'next/headers';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const cookieStore = cookies();
  const supabase = createRouteHandlerClient({ cookies: () => cookieStore });
  
  try {
    const { email, password } = await request.json();
    const { error } = await supabase.auth.signInWithPassword({ email, password });

    if (error) {
      return NextResponse.json(
        { message: '登录失败,请检查账号密码' },
        { status: 401 }
      );
    }

    return NextResponse.json({ message: '登录成功' }, { status: 200 });
  } catch (err) {
    console.error('登录出错:', err);
    return NextResponse.json(
      { message: '服务器发生意外错误' },
      { status: 500 }
    );
  }
}

2. 修正登录页面路径

将修改后的页面路径从/api/login/page.tsx改回原路径/app/login/page.tsx,确保前端请求的路由与后端路由匹配。

3. 关键错误原因

  • App Router的路由文件必须导出GET/POST等HTTP方法,不能使用Pages Router的handler函数,这是导致405(方法不允许)错误的核心原因。
  • NextApiRequest/NextApiResponse是Pages Router的专属类型,App Router中应使用Web标准的Request对象和NextResponse处理响应。

内容的提问来源于stack exchange,提问作者JS3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:13:23