实战目标与技术架构
1 ) 核心目标
开发微信小程序后端服务,实现问卷模板获取、结果上报与统计功能,并通过 Kafka Producer 将问卷数据推送至消息队列,供大数据平台实时分析。
2 ) 技术栈:
- 后端框架:NestJS(替代原 Spring Boot)
- 消息队列:Kafka
- 数据传输:HTTPS(微信小程序强制要求)
- 数据格式:JSON
3 ) 关键流程:
- 前端请求问卷模板 → 后端返回动态模板(JSON 格式)。
- 用户提交问卷 → 后端通过
Kafka Producer将结果发送至 Kafka Topic。 - 大数据平台(如 Flink/Spark)消费数据并生成统计结果。
注:本实战聚焦 Kafka Producer 集成,统计结果接口暂用本地文件模拟,实际需对接实时计算平台。
接口设计与业务逻辑
三个核心接口(HTTPS 协议):
-
获取问卷模板
- 请求:
GET /survey/template - 响应:
{ "requestId": "UUID", "result": { "templateId": "T001", "questions": [ { "id": "Q1", "content": "您最近去过哪些城市?", "options": ["北京", "上海", "广州", "深圳"] }, // 更多问题... ] } }
- 请求:
-
提交问卷结果
- 请求:
POST /survey/submit - 参数:
{ "templateId": "T001", "results": [ { "questionId": "Q1", "answer": "北京" }, // 更多答案... ] } - 关键动作:数据通过
Kafka Producer发送至 Topicsurvey-results。
- 请求:
-
获取统计结果(模拟实现)
- 请求:
GET /survey/statistics?templateId=T001 - 响应:
{ "requestId": "UUID", "result": { "templateName": "疫情行程调查", "totalSubmissions": 100, "details": [ { "questionId": "Q1", "A": 10, "B": 50, "C": 12, "D": 17 }, // 更多统计... ] } }
- 请求:
工程结构搭建与依赖配置
项目目录:
src/
├── common/ # 公共模块
│ ├── dto/ # 数据传输对象
│ ├── utils/ # 工具类
│ └── filters/ # 过滤器(如跨域处理)
├── survey/ # 问卷业务模块
│ ├── controller/ # 控制器
│ ├── service/ # 服务层
│ └── kafka/ # Kafka 生产者配置
└── main.ts # 入口文件
依赖安装:
# 核心依赖
npm install @nestjs/common @nestjs/core @nestjs/microservices
# Kafka 支持
npm install kafkajs @nestjs/microservices
# 文件操作与 JSON 处理
npm install fs-extra fast-json-stringify
核心代码实现
1 ) 统一响应格式(DTO)
// src/common/dto/base-response.dto.ts
export class BaseResponseDto<T> {
requestId: string; // 请求唯一标识
result?: T; // 业务数据
static success<T>(result?: T): BaseResponseDto<T> {
const response = new BaseResponseDto<T>();
response.requestId = this.generateRequestId();
response.result = result;
return response;
}
private static generateRequestId(): string {
return Math.random().toString(36).substring(2, 15);
}
}
2 ) Kafka 生产者服务
// src/survey/kafka/survey-producer.service.ts
import { Injectable, OnModuleInit } from '@nestjs/common';
import { Kafka, Producer, ProducerRecord } from 'kafkajs';
@Injectable()
export class SurveyProducerService implements OnModuleInit {
private producer: Producer;
async onModuleInit() {
const kafka = new Kafka({
brokers: ['localhost:9092'], // Kafka 集群地址
clientId: 'survey-service',
});
this.producer = kafka.producer();
await this.producer.connect();
}
async sendSurveyResult(record: ProducerRecord) {
await this.producer.send(record);
}
async onApplicationShutdown() {
await this.producer.disconnect();
}
}
3 ) 问卷提交接口(集成 Kafka)
// src/survey/controller/survey.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { SurveyProducerService } from '../kafka/survey-producer.service';
import { BaseResponseDto } from '../../common/dto/base-response.dto';
@Controller('survey')
export class SurveyController {
constructor(private readonly producer: SurveyProducerService) {}
@Post('submit')
async submitSurvey(@ // 发送数据至 Kafka
await this.producer.sendSurveyResult({
topic: 'survey-results',
messages: [{ value: JSON.stringify(data) }],
});
return BaseResponseDto.success();
}
}
工程示例:Kafka 生产者三种集成方案
1 ) 方案 1:同步发送(确保消息顺序)
// 在 SurveyProducerService 中添加
async sendSync(topic: string, message: any) {
await this.producer.send({
topic,
messages: [{ value: JSON.stringify(message) }],
});
}
2 ) 方案 2:异步批量发送(高性能)
// 在 SurveyProducerService 中添加
private batchMessages: Array<ProducerRecord> = [];
async sendBatch() {
if (this.batchMessages.length > 0) {
await this.producer.sendBatch({
topicMessages: this.batchMessages,
});
this.batchMessages = [];
}
}
queueMessage(topic: string, message: any) {
this.batchMessages.push({
topic,
messages: [{ value: JSON.stringify(message) }],
});
if (this.batchMessages.length >= 100) { // 批量阈值
this.sendBatch();
}
}
3 ) 方案 3:事务性发送(数据一致性)
// 初始化事务生产者
const transactionalProducer = kafka.producer({
transactionalId: 'survey-transactional-producer',
});
await transactionalProducer.connect();
await transactionalProducer.transaction().run(async ({ send }) => {
await send({
topic: 'survey-results',
messages: [{ value: JSON.stringify(data) }],
});
// 其他事务操作(如数据库更新)
});
Kafka 运维命令与配置
1 ) 创建 Topic
kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--replication-factor 1 \
--partitions 3 \
--topic survey-results
2 ) NestJS 微服务配置(main.ts)
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 连接 Kafka
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.KAFKA,
options: {
client: { brokers: ['localhost:9092'] },
consumer: { groupId: 'survey-consumer' },
},
});
await app.startAllMicroservices();
await app.listen(3000);
}
bootstrap();
关键优化与注意事项
-
HTTPS 与域名:
- 使用 Nginx 反向代理 NestJS 服务,配置 SSL 证书。
- 微信小程序要求所有接口必须通过 HTTPS 访问。
-
数据安全:
- 敏感字段加密(如用户 ID)。
- Kafka 启用 SASL/SSL 认证。
-
性能优化:
Kafka 批量发送减少网络开销(见方案 2)。- 使用
compression.type参数启用消息压缩(如gzip)。
-
错误处理:
- 实现 Kafka 消息重试机制:
await producer.send({ topic: 'survey-results', messages: [...], retry: { retries: 3 } // 最多重试 3 次 });
- 实现 Kafka 消息重试机制:
术语解释:
- Kafka Topic:消息的分类通道(如
survey-results)。 - Producer:消息生产者,负责向 Kafka 发送数据。
- Consumer:消息消费者,从 Kafka 读取数据(如 Spark/Flink 作业)。
总结
本文完整实现了基于 NestJS 的微信小程序后端服务,重点集成了 Kafka Producer 实现问卷数据异步上报,并通过三种工程方案(同步、批量、事务)满足不同场景需求。
确保接口符合微信小程序 HTTPS 规范。开发者可扩展统计模块对接实时计算平台(如 Flink),构建完整的数据处理链路

被折叠的 条评论
为什么被折叠?



