通过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
触发一个异常请求看下效果:
服务端控制台:
前端控制台: