MEAN应用中GET API返回HTML而非JSON的问题排查
问题原因及解决方案
核心问题:路由与中间件顺序错误 + 模型缺失
你的请求返回HTML而非JSON,主要由两个关键问题导致:
1. 中间件与路由顺序颠倒
在server.ts中,CORS、响应头配置等中间件被放在了所有路由之后,同时Angular Universal的通配路由app.get('*', ...)虽然在API路由之后,但如果API请求处理出错,会直接触发通配路由返回HTML页面。更关键的是,这些核心中间件根本不会被API请求执行,因为路由已经提前返回了响应。
2. Controller未导入Mongoose模型
farmerController中使用了Farmer.find(),但没有导入对应的Farmer模型,运行时会抛出错误,最终请求被通配路由拦截,返回HTML。
修复步骤
1. 调整中间件与路由顺序
将中间件配置移到所有路由之前,确保所有请求都经过CORS、JSON解析等处理:
import 'zone.js/node'; const mongoose = require('mongoose'); const express = require('express'); const cors = require("cors"); import { APP_BASE_HREF } from '@angular/common'; import { ngExpressEngine } from '@nguniversal/express-engine'; import { existsSync } from 'fs'; import { join } from 'path'; import { AppServerModule } from './src/main.server'; const dotenv = require('dotenv'); const app = express(); dotenv.config({path: './config.env'}); const farmerRoute = require('./routes/farmerRoute'); const bodyParser = require('body-parser'); // 先配置核心中间件 app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Accept", "application/json"); res.header("Content-Type", "application/json"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); const corsOptions = { "origin": "*", "methods": "GET,HEAD,PUT,PATCH,POST,DELETE", "preflightContinue": false, "optionsSuccessStatus": 204 } app.use(cors(corsOptions)); app.use(express.json()); // 移除重复的bodyParser.json(),两者功能一致 // 连接数据库 const db = process.env.DATABASE.replace('<PASSWORD>', process.env.DATABASE_PASSWORD); mongoose.connect(db, { useNewUrlParser:true, useCreateIndex:true, useFindAndModify:false }).then(con => { console.log('DB connection successful') }) // 注册API路由 app.use('/api', farmerRoute); // 最后配置Angular Universal相关路由 const distFolder = join(process.cwd(), 'dist/farmer-world/browser'); const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'; app.engine('html', ngExpressEngine({ bootstrap: AppServerModule, })); app.set('view engine', 'html'); app.set('views', distFolder); app.get('*.*', express.static(distFolder, { maxAge: '1y' })); app.get('*', (req, res) => { res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); }); const port = process.env.port || 3000; app.listen(port, () => { console.log(`app is running on ${port}`); })
2. 补全Controller的模型导入
在farmerController文件顶部导入Farmer模型(根据你的实际模型路径调整):
const Farmer = require('./../models/farmerModel'); // 替换为你的模型文件路径 exports.getAllFarmers = async (req, res) => { try { const farmers = await Farmer.find(); return res.status(200).json({ status: 'success', data: farmers }) } catch (err) { return res.status(400).json({ status:'fail', message: err.message // 建议返回错误文本而非整个错误对象 }) } }
3. 添加全局错误处理(可选)
添加全局错误中间件,确保所有错误都返回JSON格式,避免请求落到通配路由:
// 放在所有路由之后 app.use((err, req, res, next) => { err.statusCode = err.statusCode || 500; err.status = err.status || 'error'; res.status(err.statusCode).json({ status: err.status, message: err.message }); });
内容的提问来源于stack exchange,提问作者patki
相关产品推荐
相关产品推荐

