您如何实现发出异步数据库请求的 Sveltekit Post 端点?

How do you implement a Sveltekit Post endpoint which makes an async DB request?

因此,当我访问 SvelteKit post 端点时,如果我提交了一些值但它们没有通过验证检查,它工作正常。它 return 是正确的状态并且 body。但是,当它插入数据库时​​,端点 return 出现 404 错误,但它可以将用户插入数据库。我认为这是因为数据库调用是异步的并且 SvelteKit 没有等待结果 return,但不确定如何更改我的代码所以它等待并发送正确的 json 响应。

感谢您的帮助!

import type { EndpointOutput } from '@sveltejs/kit';
import bcrypt from 'bcrypt';
import { randomUUID } from 'crypto';
import db from '$lib/config/db.js';
import { roles } from '$lib/config/roles.js';
import validation from '$lib/_helpers/validation';

export async function post({
    body
}: {
    body: { firstName: string; lastName: string; emailAddress: string; password: string };
}): Promise<EndpointOutput> {
    //lets trim any whitespace on the fields
    console.log(body);
    const firstName = body?.firstName.trim();
    const lastName = body?.lastName.trim();
    const email = body?.emailAddress.trim();
    const password = body?.password.trim();
    const userRole = roles.web + roles.anonymous;
    const bcryptPassword = await bcrypt.hash(password, 10);
    const emailToken = randomUUID();
    // double check the validation on the fields in case user submits directly to this endpoint.
    if (validation.validateEmail(email) == false) {
        //console.log(email);
        return {
            status: 422,
            body: {
                message: 'Please enter a valid email address.'
            }
        };
    }
    if (validation.validatePassword(password) == false) {
        return {
            status: 422,
            body: {
                message: 'Password must be at least 6 characters.'
            }
        };
    }
    if (validation.validateNotEmpty(firstName) == false) {
        return {
            status: 422,
            body: {
                message: 'First Name is required.'
            }
        };
    }
    if (validation.validateDisplayName(lastName) == false) {
        return {
            status: 422,
            body: {
                message: 'Last Name is required.'
            }
        };
    }

//insert user
    await db.query(
        'INSERT INTO users (first_name, last_name, email, user_password, user_role, email_verification_token) VALUES (, , , , , )',
        [firstName, lastName, email, bcryptPassword, userRole, emailToken],
        (error, results) => {
            // console.log(error, results);
            if (error) {
                return {
                    status: 417,
                    body: {
                        message: error.toString()
                    }
                };
            }
            //console.log(results);
            return {
                status: 201,
                body: {
                    message: 'User created successfully'
                }
            };
        }
    );
}

更新修复

我最终使用 pg-promise 包而不是 pg 包来连接我的数据库。

以下是更新后的代码,以防有人遇到类似问题。

import type { EndpointOutput } from '@sveltejs/kit';
import bcrypt from 'bcrypt';
import { randomUUID } from 'crypto';
import { roles } from '$lib/config/roles.js';
import validation from '$lib/_helpers/validation';
import { db } from '$lib/config/db.js';

export async function post({
    body
}: {
    body: { firstName: string; lastName: string; emailAddress: string; password: string };
}): Promise<EndpointOutput> {
    //lets trim any whitespace on the fields
    console.log(body);
    const firstName = body?.firstName.trim();
    const lastName = body?.lastName.trim();
    const email = body?.emailAddress.trim();
    const password = body?.password.trim();
    const userRole = roles.web + roles.anonymous;
    const bcryptPassword = await bcrypt.hash(password, 10);
    const emailToken = randomUUID();
    // double check the validation on the fields in case user submits directly to this endpoint.
    if (validation.validateEmail(email) == false) {
        //console.log(email);
        return {
            status: 422,
            body: {
                message: 'Please enter a valid email address.'
            }
        };
    }
    if (validation.validatePassword(password) == false) {
        return {
            status: 422,
            body: {
                message: 'Password must be at least 6 characters.'
            }
        };
    }
    if (validation.validateNotEmpty(firstName) == false) {
        return {
            status: 422,
            body: {
                message: 'First Name is required.'
            }
        };
    }
    if (validation.validateDisplayName(lastName) == false) {
        return {
            status: 422,
            body: {
                message: 'Last Name is required.'
            }
        };
    }

    //check if user already exists.
    const userAlreadyExists = await db.oneOrNone('SELECT email from users WHERE email= LIMIT 1', [
        email
    ]);
    console.log(' result: ' + userAlreadyExists);
    if (userAlreadyExists) {
        return {
            status: 409,
            body: {
                message: 'User with that email already exists'
            }
        };
    }

    try {
        // insert New user into DB
        await db.none(
            'INSERT INTO users (first_name, last_name, email, user_password, user_role, email_verification_token) VALUES (, , , , , )',
            [firstName, lastName, email, bcryptPassword, userRole, emailToken]
        );

        return {
            status: 201,
            body: {
                message: 'User created successfully'
            }
        };
    } catch (error) {
        return {
            status: 417,
            body: {
                message: error.toString()
            }
        };
    }
}

您的问题是您使用的数据库是通过回调系统实现的 function query(queryString, callback) 而您的 await 不会 wait,也不回调中的 return 实际上是端点之外的 return。

最好的办法是检查你的数据库库是否有异步方法,你可以在其中执行类似这样或类似的操作:

const { errror, result } = await db.query(....)

这样应用程序实际上会等待查询完成。