成功解决:node作BFF,整合数据,转发请求

问题

项目设计为双后台。

一个是python后台,返回的通用数据,数据都比较原子化。

一个是node后台,作为BFF(Backends For Frontends 服务于前端的后端),为前端提供整合好的数据。

node作为中间服务器,需要多次请求python后台数据,并将其整合成前端需要的形式

本文的问题便是如何整合后台数据并返回

前置信息

python提供的接口:

spu接口

const API = '/spu?spu=spuname'

const response = {
	code: 200,
	msg: '业务成功',
	data: {
		name: 'spu_name',
		title: 'spu_title',
		pictures: 'pictures',
		skus: [
			'sku1_name',
			'sku2_name',
			'sku3_name',
		]
	}
};

 

sku接口

const API = '/sku?sku=sku_name'

const repsonse = {
	code: 200,
	msg: '业务成功',
	data: {
		name: 'sku_name',
		details: 'details',
		pictures: 'pictures',
		price: '3.99',
	}
}

 

必要的解释

spu:Standard Product Unit,标准产品单元

sku:Stock Keeping Unit,最小货存单位

第一张图,iPhone12mini,这个就是spu,无论是蓝色、绿色,64GB、128GB都是iPhone12mini

第二张图,iPhone12mini-无需合约版-绿色-64GB,这个就是sku,确定到库存里最小最细的一类库存

node 目标接口:

预期封装接口

const API = '/spu/details?sku=sku_name'

const response = {
	code: 200,
	msg: '业务成功',
	data: {
		name: 'spu_name',
		title: 'spu_title',
		pictures: 'spu_pictures',
		skus: [
			{
				name: 'sku1_name',
				details: 'sku1_details',
				pictures: 'sku1_pictures',
				price: '1.00',
			},
			{
				name: 'sku2_name',
				details: 'sku2_details',
				pictures: 'sku2_pictures',
				price: '2.00',
			},
			{
				name: 'sku3_name',
				details: 'sku3_details',
				pictures: 'sku3_pictures',
				price: '3.00',
			},
		]
	}
}

 

最终代码

const express = require('express')
const http = require('http')
const axios = require('axios')

var app = express()

const remote = "127.0.0.1"
const port = 8080
const running_port = 3000
const hostname = `http://${remote}:${port}`

app.get('/spu/details', async function(req, res){
    var params = req.query
	var spu = params.spu
	spu = await axios.get(`${hostname}/spu?spu=${spu}`)
	spu = spu.data.data
	if(!spu){
		res.status(500).json({error: '服务器错误'})
	}
	var result = []
	for(sku of spu.skus){
		sku = axios.get(`${hostname}/sku?sku=${sku}`)
		result.push(sku)
	}
	result = await axios.all(result)
	if(!result){
		res.status(500).json({error: '服务器错误'})
	}
	spu.skus = result.map(res => res.data.data)
    res.send(spu)
})

app.all('*', (req, res) => {
	const option = {
      hostname: remote,
      port: port,
      path: req.originalUrl,
      method: req.method,
      headers: req.headers,
	}
	const request = http.request(option, async function(response){
		res.statusCode = response.statusCode
		for(key in response.headers){
			res.header(key, response.headers[key])
		}
		response.pipe(res)
	})
	request.on('error', function(error){
		console.log(error)
	})
    req.pipe(request)
})
.listen(running_port, function(){
    console.log(`Server running on running port ${running_port}`)
})

代码解释

app.get('/spu/details', ...)

async (异步)是javascript里异步函数的标志,如果函数中使用了await(等待)关键字,那么必须将函数声明为异步
async函数返回的是一个Promise对象(一个承诺我会最终有结果的对象^_^),意思是这个会有返回值,但是现在暂时还没有
awai的意思就是函数在这里暂停,当必须得到这个对象里面的一些数据的时候使用
这里我们需要知道spu下面有哪些sku,所以必须等结果出来

axios,是一个异步请求函数库,不使用await函数会返回一个Promise对象
因为sku的获取之间并没有操作是需要互相之间等待的,所以在循环里面,将全部的sku请求发了出去
await axios.all 是等待这个数组里面的所有Promise出结果,这个是一个出错,整个函数就返回错误
result.map 是数组类型的一个方法,返回一个新数组,作用如下图

可以看到,数组的map方法不会改变原数组
原数组中的每个值,都会作为输入,输入到函数之中,得到新的结果
返回这些新结果组成的新数组

app.all('*', ...)

app.all 是接受所有请求的接口,post、get、delete、patch等等方法都会进入这个地方
app.all('*', ()=>{}), *号的意思是接受所有路径的请求
两个联合起来就是接受所有端口,所有路径的意思
这里实现的功能是转发所有的请求

*不会让'/spu/details'接受不到请求吗?
不会。这个express使用的是匹配准确度更高,就优先使用的原则

猜你喜欢

转载自blog.csdn.net/Gragon_Shao/article/details/112748535