Next.js App Router中删除API的albumName查询参数未定义问题
删除专辑API中
albumName未定义的问题排查与解决 问题描述
我正在开发一个Delete API,用于从MongoDB Atlas的用户文档中删除专辑,但始终遇到albumName属性未定义的错误,找不到原因。用户可以在页面选择要删除的专辑触发操作,数据库中用户的albums是专辑对象数组,每个专辑包含albumName和outfits(数组)两个属性。
Delete API代码
import { connect } from "@/dbConfig/dbConfig"; import User from "@/models/userModel"; import { NextRequest, NextResponse } from "next/server"; import jwt from "jsonwebtoken"; connect(); export async function DELETE(request) { const token = request.cookies.get("token")?.value || ''; const decodedToken = jwt.decode(token); const email = decodedToken ? decodedToken.email : ''; const albumName = request.query.albumName; // Extract albumName from query params try { const userEmail = email.toLowerCase(); if (!userEmail || !albumName) { return NextResponse.json({ error: "Email or albumName not provided" }, { status: 400 }); } const user = await User.findOneAndUpdate( { email: userEmail }, { $pull: { albums: { albumName: albumName } } }, { new: true } ); if (!user) { return NextResponse.json({ error: "User not found" }, { status: 404 }); } if (!user.albums.find(album => album.albumName === albumName)) { return NextResponse.json({ error: "Album not found in user's albums" }, { status: 404 }); } return NextResponse.json({ success: true, message: "Album deleted successfully" }); } catch (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } }
Albums 页面代码
'use client'; import { useEffect, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faTrashCan } from '@fortawesome/free-solid-svg-icons' import Link from 'next/link'; import axios from 'axios'; export default function AlbumsPage() { const [albumName, setAlbumName] = useState(''); const [albums, setAlbums] = useState([]); const [showModal, setShowModal] = useState(false); const [deleteAlbumName, setDeleteAlbum] = useState(''); const [errorMessage, setErrorMessage] = useState(''); const fetchAlbums = async () => { try { const response = await axios.get('/api/users/getUserAlbums'); setAlbums(response.data.albums); } catch (error) { console.log(error); } }; useEffect(() => { fetchAlbums(); }, []); const handleCreateAlbum = () => { setShowModal(true); setErrorMessage(''); }; const handleModalInputChange = (e) => { setAlbumName(e.target.value); setErrorMessage(''); }; const handleModalClose = () => { setShowModal(false); setAlbumName(''); }; const handleModalSubmit = async () => { try { const response = await axios.post('/api/users/createAlbums', { albumName }); console.log(albumName); setAlbums(prevAlbums => [...prevAlbums, { albumName }]); setShowModal(false); setAlbumName(''); } catch (error) { if (error.response) { if (error.response.status === 400) { setErrorMessage('Album already exists'); } else { setErrorMessage('Failed to create album'); } } else { setErrorMessage('Network error. Please try again.'); } } }; const handleDeleteAlbum = async (albumName) => { setDeleteAlbum(albumName); setShowModal(true); }; const confirmDeleteAlbum = async () => { if (deleteAlbumName) { console.log('Deleting album:', deleteAlbumName); // Log the album name try { const response = await axios.delete(`api/users/deleteAlbums?albumName=${deleteAlbumName}`); setShowModal(false); setDeleteAlbum(''); fetchAlbums(); } catch (error) { console.log(error); console.log('Failed to delete album'); } } }; useEffect(() => { const handleKeyPress = (event) => { if (event.key === 'Enter') { event.preventDefault(); handleModalSubmit(); } }; document.addEventListener('keydown', handleKeyPress); return () => { document.removeEventListener('keydown', handleKeyPress); }; }, [albumName]); return ( <main> {showModal && ( <div className="fixed top-0 left-0 w-full h-full flex items-center justify-center bg-gray-500 bg-opacity-50 z-50"></div> )} {showModal && ( <div className="fixed top-0 left-0 w-full h-full flex items-center justify-center z-50"> <div className="bg-white p-10 rounded-md shadow-lg"> {deleteAlbumName ? ( <> <h2 className="text-lg font-semibold mb-2">Are you sure you want to delete this album?</h2> <div className="flex items-center justify-center"> <button className="bg-black text-white px-4 py-2 rounded-md mr-2 font-semibold" onClick={confirmDeleteAlbum}>Yes</button> <button className="bg-gray-300 text-gray-800 px-4 py-2 rounded-md font-semibold" onClick={handleModalClose}>No</button> </div> </> ) : ( <> <h2 className="text-lg font-semibold mb-2">Enter Album Name</h2> {errorMessage && <p className='text-sm text-red-500 mb-2'>{errorMessage}</p>} <input type="text" className="border border-gray-300 rounded-md p-2 mb-2 outline-none" value={albumName} onChange={handleModalInputChange} placeholder='Album Name' /> <div className="flex items-center justify-center"> <button className="bg-black text-white px-4 py-2 rounded-md mr-2 font-semibold" onClick={handleModalSubmit}>Create</button> <button className="bg-gray-300 text-gray-800 px-4 py-2 rounded-md font-semibold" onClick={handleModalClose}>Cancel</button> </div> </> )} </div> </div> )} <div className="flex flex-col items-center justify-center bg-gray-300 shadow-lg p-4"> <h1 className="font-bold text-3xl mb-4">Albums</h1> <button className="bg-black text-white px-4 py-2 rounded-xl mb-4 font-semibold" onClick={handleCreateAlbum}> Create Album </button> </div> <div className="grid grid-cols-3 gap-4 m-5"> {albums.map((album, index) => ( album && album.albumName && ( <div key={index} className="bg-white rounded-lg shadow-md p-4 relative text-center"> <Link href={`/albums/${album.albumName}`} className="text-lg font-semibold mb-2 hover:opacity-70">{album.albumName}</Link> <button className="absolute bottom-0 right-0 bg-transparent text-white px-4 py-2 rounded-md font-semibold" onClick={() => handleDeleteAlbum(album.albumName)} title='Delete Album' > <FontAwesomeIcon icon={faTrashCan} className='text-red-500' /> </button> </div> ) ))} </div> </main> ); }
问题分析
API端查询参数获取方式错误:在Next.js App Router的
DELETE路由函数中,不能直接通过request.query获取URL查询参数,正确的方式是使用request.nextUrl.searchParams。原代码中request.query.albumName会导致albumName始终为undefined。前端请求URL路径错误:
confirmDeleteAlbum中的axios请求URL缺少开头的/,会导致请求路径被解析为相对路径,可能无法正确到达API端点,进而导致查询参数传递失败。
修复方案
1. API端修复
修改API中获取albumName的代码,替换为正确的查询参数获取方式:
// 替换原有的const albumName = request.query.albumName; const albumName = request.nextUrl.searchParams.get('albumName') || '';
如果专辑名称包含特殊字符,建议添加解码处理:
const albumName = decodeURIComponent(request.nextUrl.searchParams.get('albumName') || '');
2. 前端修复
修改confirmDeleteAlbum中的请求URL,添加开头的/,确保是绝对路径:
// 替换原有的axios.delete(`api/users/deleteAlbums?albumName=${deleteAlbumName}`); const encodedAlbumName = encodeURIComponent(deleteAlbumName); const response = await axios.delete(`/api/users/deleteAlbums?albumName=${encodedAlbumName}`);
使用encodeURIComponent编码专辑名称,避免特殊字符导致的参数传递错误。
额外优化(可选)
在API的校验逻辑中,可以补充对albumName的空值判断,确保逻辑严谨:
if (!userEmail || !albumName.trim()) { return NextResponse.json({ error: "Email or albumName not provided" }, { status: 400 }); }
内容的提问来源于stack exchange,提问作者gj_dev
相关产品推荐
相关产品推荐

