我正在使用NestJS与MongoDB创建自定义API。我有以下设置:
// users.controller.ts
@Post('sign-up')
@UseFilters(MongoExceptionFilter)
async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
return await this.userService.signUp(createUserDto).catch(error => {
throw new BadRequestException(error);
});
}
// user.service.ts
async signUp(createUserDto: CreateUserDto): Promise<User> {
const createUser = new this.userModel(createUserDto);
return await createUser.save();
}
// mongo-exception.filter.ts
import { ArgumentsHost,Catch, ConflictException, ExceptionFilter } from '@nestjs/common';
import { MongoError } from 'mongodb';
@Catch(MongoError)
export class MongoExceptionFilter implements ExceptionFilter {
catch(exception: MongoError, host: ArgumentsHost) {
console.log('>>>>>>>>>>>>>>>>>>>> exception: ', exception);
}
}
// package.json
"dependencies": {
"@nestjs/common": "^5.4.0",
"@nestjs/core": "^5.4.0",
"@nestjs/jwt": "^0.2.1",
"@nestjs/mongoose": "^5.2.2",
"@nestjs/passport": "^5.1.0",
"@nestjs/typeorm": "^5.2.2",
"fancy-log": "^1.3.3",
"mongoose": "^5.4.7",
"nestjs-config": "^1.3.0",
"passport": "^0.4.0",
"passport-http-bearer": "^1.0.1",
"passport-jwt": "^4.0.0",
"reflect-metadata": "^0.1.12",
"rimraf": "^2.6.2",
"rxjs": "^6.2.2",
"typeorm": "^0.2.12",
"typescript": "^3.0.1",
"util": "^0.11.1"
},
现在,无论何时我对/ sign-up路由进行POST调用,都应在save()
中调用user.service.ts
。所有这一切。接下来,当我再次发布/ sign-up路由时,它应该触发MongoDB错误,因为具有相同电子邮件地址的用户已经存在(电子邮件地址是唯一的,因此密钥重复)。我只在将错误记录在.catch(err => ...);
中时看到该错误,但是问题是自定义MongoExceptionFilter
。我不会触发MongoError。当我将@Catch()
留为空白时,它会触发但无法处理异常。
我在做什么错?自从我看到this帖子并将其用作基础以来,我似乎无法使其正常工作。是Mongoose或NestJS的更新,为什么它不再起作用了?
答案 0 :(得分:1)
这是因为您将所有错误都转换为BadRequestExceptions
,因此您的MongoExceptionFilter
不承担任何责任;它会检查instanceof MongoError
返回BadRequestException
为false的return await this.userService.signUp(createUserDto).catch(error => {
throw new BadRequestException(error);
});
:
.catch()
这发生在运行异常过滤器之前;他们总是跑到最后。
从您的控制器中删除@Catch()
export class BadRequestFilter implements ExceptionFilter {
catch(exception: Error, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse();
response.status(400).json({message: exception.message});
}
}
。如果您真的想将所有其他异常转换为BadRequestExceptions(400),则可以编写第二个异常过滤器,该过滤器处理MongoExceptionFilter未处理的所有异常:
@Catch(MongoError)
export class MongoFilter implements ExceptionFilter {
catch(exception: MongoError, host: ArgumentsHost) {
const response = host.switchToHttp().getResponse();
if (exception.code === 11000) {
response.status(400).json({ message: 'User already exists.' });
} else {
response.status(500).json({ message: 'Internal error.' });
}
}
}
和
@UseFilters(BadRequestFilter, MongoFilter)
async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
然后将两者都添加到您的控制器中(顺序很重要!):
/* Instantiate instantsearch.js */
var search = instantsearch({
appId: algolia.application_id,
apiKey: algolia.search_api_key,
indexName: algolia.indices.searchable_posts.name,
urlSync: {
mapping: {'q': 's'},
trackedParameters: ['query']
},
searchParameters: {
facetingAfterDistinct: true,
highlightPreTag: '__ais-highlight__',
highlightPostTag: '__/ais-highlight__'
}
});
/* Search box widget */
search.addWidget(
instantsearch.widgets.searchBox({
container: '#algolia-search-box',
placeholder: 'Search ...',
searchAsYouType: false,
wrapInput: false,
poweredBy: algolia.powered_by_enabled
})
);
/* Hits widget */
search.addWidget(
instantsearch.widgets.hits({
container: '#algolia-hits',
hitsPerPage: 10,
templates: {
empty: 'No results were found for "<strong>{{query}}</strong>".',
item: wp.template('instantsearch-hit')
},
transformData: {
item: function (hit) {
function replace_highlights_recursive (item) {
if( item instanceof Object && item.hasOwnProperty('value')) {
item.value = _.escape(item.value);
item.value = item.value.replace(/__ais-highlight__/g, '<em>').replace(/__\/ais-highlight__/g, '</em>');
} else {
for (var key in item) {
item[key] = replace_highlights_recursive(item[key]);
}
}
return item;
}
hit._highlightResult = replace_highlights_recursive(hit._highlightResult);
hit._snippetResult = replace_highlights_recursive(hit._snippetResult);
console.log(hit);
if ( hit.post_excerpt != '' ){
hit._snippetResult['content']['value'] = hit.post_excerpt;
}
if ( hit.short_title.length > 0 && hit.short_title[0] != '' ){
hit._highlightResult['post_title']['value'] = hit.short_title[0];
}
return hit;
}
}
})
);
/* Pagination widget */
search.addWidget(
instantsearch.widgets.pagination({
container: '#algolia-pagination'
})
);
/* Tags refinement widget */
search.addWidget(
instantsearch.widgets.refinementList({
container: '#facet-tags',
attributeName: 'taxonomies.aar_article_type',
operator: 'and',
limit: 15,
sortBy: ['isRefined:desc', 'count:desc', 'name:asc'],
templates: {
header: '<h2 class="widgettitle">Filter Results</h2>'
}
})
);
/* Start */
search.start();