mongodb TypeError:无法读取undefined的属性(正在阅读'json')

8xiog9wr  于 2023-05-28  发布在  Go
关注(0)|答案(1)|浏览(160)

TypeError:无法读取undefined的属性(阅读'json')

嗨,我正在使用TypeScript和node/Next.js 13以及新的应用程序路由器和mongoose将数据推送到Mongo数据库中,但它一直向我发送这个错误:“类型错误:无法读取undefined的属性(阅读'json')"。有效负载显示在浏览器的Network部分,但不会传递到数据库。我是Next.js和TypeScript的新手,所以如果我错过了一些明显的东西,我很抱歉,但我非常绝望,我已经尝试了许多解决方案,没有一个有帮助。提前谢谢!

创建新产品时尝试将数据传递到数据库。

product/new/page.tsx

"use client"

import Plan from "@/app/components/Plan";
import axios from "axios";
import { useState } from "react";

export default function NewProduct() {
    const [title, setTitle] = useState('');
    const [description, setDescription] = useState('');
    const [price, setPrice] = useState('');
    async function createProduct(ev:any) {
        ev.preventDefault();
        await axios.post('../../api/products', {title, description, price});
    }

    return (
        <Plan>
            <div className="max-w-md mx-auto mt-14">
                <h2 className="text-2xl font-bold mb-4">Pievienot jaunu preci</h2>
                <form onSubmit={ createProduct }>
                    <div className="mb-4">
                        <label htmlFor="productName" className="block text-gray-700 text-sm font-bold mb-2">
                            Preces nosaukums:
                        </label>
                        <input
                            type="text"
                            className="appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            placeholder="Ievadiet preces nosaukumu"
                            value={title}
                            onChange={ev => setTitle(ev.target.value)}
                        />
                        </div>
                        <div className="mb-4">
                        <label htmlFor="description" className="block text-gray-700 text-sm font-bold mb-2">
                            Apraksts:
                        </label>
                        <textarea
                            className="appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            placeholder="Ievadiet preces aprakstu"
                            value={description}
                            onChange={ev => setDescription(ev.target.value)}
                        />
                        </div>
                        <div className="mb-4">
                        <label htmlFor="price" className="block text-gray-700 text-sm font-bold mb-2">
                            Cena:
                        </label>
                        <input
                            type="text"
                            className="appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                            placeholder="Ievadiet preces cenu"
                            value={price}
                            onChange={ev => setPrice(ev.target.value)}
                        />
                        </div>
                        <div className="flex items-center justify-end">
                        <button
                            type="submit"
                            className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
                            Pievienot
                        </button>
                    </div>
                </form>
            </div>
        </Plan>
    )
}

src/app/API/products/page.ts

import { NextApiRequest, NextApiResponse } from "next";
import { NextResponse } from "next/server";
import { mongooseConnect } from "../../../../lib/mongoose";
import { Product } from "../../../../models/Product";

export default async function handle(req: NextApiRequest, res: NextApiResponse) {
        const { method } = req;
        await mongooseConnect();
            console.log({res})
            console.log({req})
            const { title, description, price } = req.body || {};
            const productDoc = await Product.create({
                title,
                description,
                price,
            });
            const data = res.json(productDoc);
            return NextResponse.json(data);
}

调试res.json时,Console返回:{ res: undefined } { req: { params: {}, searchParams: {} } }

models/Product.ts

import mongoose, { Schema } from "mongoose";

const ProductSchema = new Schema({
    title: String,
    description: String,
    price: Number,
});

export const Product = mongoose.models.Product || mongoose.model('Product', ProductSchema);

lib/mongoose.ts

import mongoose from "mongoose";

export function mongooseConnect() {
    const uri = process.env.MONGODB_URI;
    if (mongoose.connection.readyState === 1) {
        return Promise.resolve(mongoose.connection);
    } else {
        return mongoose.connect(uri!);
    }
}

lib/mongodb.ts

// This approach is taken from https://github.com/vercel/next.js/tree/canary/examples/with-mongodb
import { MongoClient } from "mongodb";

if (!process.env.MONGODB_URI) {
  throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
}

const uri = process.env.MONGODB_URI;
const options = {};

let client;
let clientPromise: Promise<MongoClient>;

if (process.env.NODE_ENV === "development") {
  // In development mode, use a global variable so that the value
  // is preserved across module reloads caused by HMR (Hot Module Replacement).
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options);
    global._mongoClientPromise = client.connect();
  }
  clientPromise = global._mongoClientPromise;
} else {
  // In production mode, it's best to not use a global variable.
  client = new MongoClient(uri, options);
  clientPromise = client.connect();
}

// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "models/Product.js", "src/app/api/products/page.js", "src/app/api/products.js"],
  "exclude": ["node_modules"]
}
sf6xfgos

sf6xfgos1#

你的API handle函数失败了。

export default async function handle(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // always run async code inside try/catch
  try {
    const { method } = req;
    await mongooseConnect();
    console.log({ res });
    console.log({ req });
    const { title, description, price } = req.body || {};
    // since in schema, title, description, price are required, make sure you sent all
    if (!title || !description || !price){
      console.error("if you are here means you did not pass those correctly")
      // handle accordingly
    }
    const productDoc = await Product.create({
      title,
      description,
      price,
    });
    const data = res.json(productDoc);
    return NextResponse.json(data);
  } catch (error) {
    console.error("error in handler", error);
  }
}

相关问题