博客评论限流5/min,添加前端错误处理

This commit is contained in:
2025-06-19 15:42:38 +08:00
parent 325c2e3a87
commit bf3b2f7a94
2 changed files with 23 additions and 16 deletions

View File

@@ -3,23 +3,25 @@ import {
Body, Body,
Controller, Controller,
Get, Get,
Ip,
Param, Param,
ParseUUIDPipe, ParseUUIDPipe,
Post, Post,
Request, Req,
UseGuards, UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { BlogService } from './blog.service'; import { BlogService } from './blog.service';
import { OptionalAuthGuard } from 'src/auth/strategies/OptionalAuthGuard'; import { OptionalAuthGuard } from 'src/auth/strategies/OptionalAuthGuard';
import { UserService } from 'src/user/user.service'; import { UserService } from 'src/user/user.service';
import { createBlogCommentDto } from './dto/create.blogcomment.dto'; import { createBlogCommentDto } from './dto/create.blogcomment.dto';
import { Throttle, ThrottlerGuard } from '@nestjs/throttler';
@Controller('blog') @Controller('blog')
export class BlogController { export class BlogController {
constructor( constructor(
private readonly blogService: BlogService, private readonly blogService: BlogService,
private readonly userService: UserService, private readonly userService: UserService,
) {} ) { }
@Get() @Get()
getBlogs() { getBlogs() {
@@ -54,25 +56,22 @@ export class BlogController {
} }
// 该接口允许匿名评论但仍需验证userId合法性 // 该接口允许匿名评论但仍需验证userId合法性
@UseGuards(OptionalAuthGuard) @UseGuards(ThrottlerGuard, OptionalAuthGuard)
@Throttle({ default: { limit: 5, ttl: 60000 } })
@Post(':id/comment') @Post(':id/comment')
async createBlogComment( async createBlogComment(
@Param('id', new ParseUUIDPipe({ version: '4' })) id: string, @Param('id', new ParseUUIDPipe({ version: '4' })) id: string,
@Body() commentData: createBlogCommentDto, @Body() commentData: createBlogCommentDto,
@Request() req, @Req() req,
@Ip() ip,
) { ) {
const { userId } = req.user || {}; const { userId } = req.user || {};
const blog = await this.blogService.findById(id); const blog = await this.blogService.findById(id);
if (!blog) throw new BadRequestException('文章不存在'); if (!blog) throw new BadRequestException('文章不存在');
const user = userId ? await this.userService.findOne({ userId }) : null; const user = userId ? await this.userService.findById(userId) : null;
// 获取IP归属地 // 获取IP归属地
const ip =
req.ip ||
req.socket.remoteAddress ||
req.headers['x-forwarded-for'] ||
'未知';
let address = '未知'; let address = '未知';
if (!['::1'].includes(ip)) { if (!['::1'].includes(ip)) {
const addressRes = await ( const addressRes = await (

View File

@@ -32,12 +32,20 @@ export function BlogCommentTool({ blogId, onInsertComment, replayTarget, handleC
const submit = async () => { const submit = async () => {
if (comment.trim().length === 0) return; if (comment.trim().length === 0) return;
const res = await BlogApi.createComment(blogId, comment, replayTarget ? replayTarget.id : undefined);
if (res) { try {
toast.success('发布成功'); const res = await BlogApi.createComment(blogId, comment, replayTarget ? replayTarget.id : undefined);
setComment(''); if (res) {
onInsertComment(res); toast.success('发布成功');
handleClearReplayTarget(); setComment('');
onInsertComment(res);
handleClearReplayTarget();
}
} catch (error: any) {
if (error.statusCode === 429) {
return toast.error('操作太频繁了,稍后再试吧')
}
toast.error('发布失败')
} }
} }