记录使用expres.js 的模块化开发一个简单的web服务器

文章描述了一个使用Express.js搭建的Web服务器,该服务器主要功能是调用高德地图的地理编码查询接口。通过路由模块化管理,将不同路由分配到不同的文件,实现了代码的清晰结构。在遇到错误时,应用全局异常处理中间件进行捕获。此外,还展示了如何封装一个针对高德地图的HTTP请求组件,利用axios库进行网络请求,并在请求和响应中添加了拦截器进行错误处理和数据验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过express.js搭建了一个简单的web服务器,功能目前只有一个,就是通过这个web服务器去访问高德的地理编码查询接口,并把高德返回的数据返回给客户端

地址访问我这里用到了express的router模块来做,但是如果把所有 的地址访问都放在同一个文件中,文件会显得极度的臃肿并且难以排查问题,所以,我把router做了模块化的管理

这张图里面的结构,是我希望完成的路由模块化的结构:

请添加图片描述

上面的图片展示的是项目的文件结构
其中 routers文件夹下的index.js就是项目的总路由文件,里面放置后续所有一级路由的中间件
controllers文件夹是业务逻辑处理的所有中间件

server.js:

const express = require('express')
const app = express()

const router = require('./routers/index')

//
app.use(router)

//全局的异常捕获
app.use((err, req, res, next) => {
    console.log('发生了错误:' + JSON.stringify(err))
    res.send({code: 500, msg: '服务器内部异常', data: null})
})

app.listen(3006, () => {
    console.log('服务开启')
})

routers/index.js:
路由大总管,所有的一级路由同放在这个文件中统一管理

const express = require('express');
const router = express.Router();
const amapApiRouter = require('../controllers/amap/indexRouter')

router.use('/amap', amapApiRouter)

module.exports = router

//router.use 即为使用路由级别的中间件,访问/amap前缀的相关链接,都会调用后面的中间件
//这里我只写了一个路由前缀,如果有其他的路由前缀都放在这个文件里统一管理

controllers/indexRouter.js:

const router = require('express').Router()

const geoController   = require('./geo/controller')
const regeoController = require('./regeo/controller')


router.get('/getGeoData', new geoController().getData)
router.get('/getRegeoData', new regeoController().getData)
 
module.exports = router

//这个http组件是我个人封装的一个针对高德地图做http请求的组件,可根据项目要求自己定义,最后会贴一下代码,因为与全局错误处理有关
const http = require('../../../apis/amap/request')

//这个就是处理具体业务的controller,因为express使用中间件要求为函数类型
//为了一个controller能多干活并且满足框架的传参类型,我将controller定义为了一个class,这样可以轻松调用内部函数来作为框架中间件的传参
module.exports = class GeoController {
//函数的req,res,next形参是所有中间件共享的,会从起始一直流转至本次业务处理结束,所以无需纠结参数可以直接使用
    getData = function(req, res, next) {
        let address = req.query.address //地址信息 ex: 石家庄市北国商城
        let city = req.query.city //指定查询的城市 默认全国查询
        http.get(`geocode/ge?city=${city}&address=${address}`).then(response => {
            res.status(200).send({code: 0, msg: 'SUCCESS', data: response.geocodes})
        }).catch(err => {
        //这里需要注意,如果想用全局的错误处理中间件,这里需要调用中间件共享的next函数,将捕获到的异常流转下去
            next(err)
        })
    }
}

apis/amap/request.js:
封装的针对高德那边的http处理组件,使用的是axios库,这玩意前端和node都能使,不比那个request库香?只不过需要注意版本问题,node版本低会报错

const axios = require('axios')
const fs = require('fs')

let codeInfo = JSON.parse(fs.readFileSync(__dirname + '/amap_api_infoCode_description.txt', 'utf-8'))

const http = axios.create({
  baseURL: 'https://restapi.amap.com/v3/',
  timeout: 1000 * 120,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json; charset=utf-8',
    'Accept-Language': 'zh-CN'
  }
})

/**
 * 请求拦截
 */
http.interceptors.request.use(config => {
  config.url = config.url + '&key=高德的APIKEY'
  return config
}, error => {
  return Promise.reject(error)
})

/**
 * 响应拦截
 */
http.interceptors.response.use(response => {
  return new Promise((resolve, reject) => {
    // console.log(response)
    if (!response) {
      throw new Error('异常请求')
    } else {
      if (response.status !== 200) {
        throw new Error('接口请求失败')
      } else {
        if (response.data) {
          if (response.data.status !== '1') {
          //抛出异常,异常需要被promise的catch回调函数处理并通过中间件的next做流转才可以被异常处理的中间件接收
            reject({error_type: 'AMAP_API_ERROR', error_info: codeInfo[response.data.infocode].info, error_msg: codeInfo[response.data.infocode].description})
          } else {
            resolve(response.data)
          }
        }
      }
    }
  })
}, error => {
  console.log(error)
  return Promise.reject(error)
})

module.exports = http

触发一个异常请求看下效果:
服务端控制台:
请添加图片描述
前端控制台:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值