阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 与Node.js后端开发

与Node.js后端开发

作者:陈川 阅读数:21290人阅读 分类: TypeScript

Node.js 后端开发概述

Node.js 已成为现代后端开发的重要工具,其非阻塞 I/O 和事件驱动架构特别适合构建高性能网络应用。结合 TypeScript 的类型系统,可以显著提升代码质量和开发体验。TypeScript 为 JavaScript 添加了静态类型检查,使得大型 Node.js 应用更易于维护和扩展。

TypeScript 与 Node.js 环境配置

要在 Node.js 项目中使用 TypeScript,首先需要安装必要的依赖:

npm init -y
npm install typescript ts-node @types/node --save-dev

创建 tsconfig.json 文件配置 TypeScript 编译器:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Express 框架的类型化开发

使用 TypeScript 开发 Express 应用时,类型定义能显著减少错误:

import express, { Request, Response, NextFunction } from 'express';

interface User {
  id: number;
  name: string;
}

const app = express();
app.use(express.json());

const users: User[] = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

app.get('/users', (req: Request, res: Response) => {
  res.json(users);
});

app.post('/users', (req: Request<{}, {}, User>, res: Response) => {
  const newUser = req.body;
  users.push(newUser);
  res.status(201).json(newUser);
});

数据库交互的类型安全

使用 TypeORM 进行类型安全的数据库操作:

import { Entity, PrimaryGeneratedColumn, Column, createConnection } from 'typeorm';

@Entity()
class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

async function main() {
  const connection = await createConnection({
    type: 'postgres',
    host: 'localhost',
    port: 5432,
    username: 'test',
    password: 'test',
    database: 'test',
    entities: [User],
    synchronize: true
  });

  const userRepository = connection.getRepository(User);
  
  const newUser = new User();
  newUser.name = 'Charlie';
  newUser.email = 'charlie@example.com';
  
  await userRepository.save(newUser);
  
  const users = await userRepository.find();
  console.log(users);
}

main();

中间件的类型化实现

创建类型安全的 Express 中间件:

import { RequestHandler } from 'express';

interface AuthRequest extends Request {
  user?: {
    id: number;
    role: string;
  };
}

const authMiddleware: RequestHandler = (req: AuthRequest, res, next) => {
  // 模拟认证逻辑
  req.user = {
    id: 1,
    role: 'admin'
  };
  next();
};

const adminMiddleware: RequestHandler<{}, {}, {}, {}, AuthRequest> = (req, res, next) => {
  if (req.user?.role !== 'admin') {
    return res.status(403).json({ error: 'Forbidden' });
  }
  next();
};

错误处理的类型化模式

实现类型化的错误处理中间件:

class AppError extends Error {
  constructor(
    public statusCode: number,
    message: string,
    public isOperational = true
  ) {
    super(message);
    Object.setPrototypeOf(this, new.target.prototype);
    Error.captureStackTrace(this, this.constructor);
  }
}

const errorHandler: ErrorRequestHandler = (
  err: AppError,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  err.statusCode = err.statusCode || 500;
  
  res.status(err.statusCode).json({
    status: 'error',
    message: err.message,
    stack: process.env.NODE_ENV === 'development' ? err.stack : undefined
  });
};

配置管理的类型安全

使用类型化的环境变量管理:

import * as dotenv from 'dotenv';
dotenv.config();

interface EnvVars {
  PORT: number;
  DATABASE_URL: string;
  JWT_SECRET: string;
  NODE_ENV: 'development' | 'production' | 'test';
}

const env: EnvVars = {
  PORT: parseInt(process.env.PORT || '3000'),
  DATABASE_URL: process.env.DATABASE_URL || '',
  JWT_SECRET: process.env.JWT_SECRET || 'secret',
  NODE_ENV: (process.env.NODE_ENV as EnvVars['NODE_ENV']) || 'development'
};

function assertEnvVars(env: Partial<EnvVars>): asserts env is EnvVars {
  if (!env.DATABASE_URL) {
    throw new Error('DATABASE_URL is required');
  }
  if (!env.JWT_SECRET) {
    throw new Error('JWT_SECRET is required');
  }
}

assertEnvVars(env);

测试的类型化方法

使用 Jest 进行类型化的测试:

import request from 'supertest';
import app from '../app';

describe('User API', () => {
  describe('GET /users', () => {
    it('should return all users', async () => {
      const response = await request(app)
        .get('/users')
        .expect(200);
      
      expect(response.body).toEqual([
        { id: 1, name: 'Alice' },
        { id: 2, name: 'Bob' }
      ]);
    });
  });

  describe('POST /users', () => {
    it('should create a new user', async () => {
      const newUser = { name: 'Charlie' };
      
      const response = await request(app)
        .post('/users')
        .send(newUser)
        .expect(201);
      
      expect(response.body).toMatchObject(newUser);
      expect(response.body.id).toBeDefined();
    });
  });
});

性能优化的类型安全方法

类型化的缓存实现:

interface CacheStore<T> {
  get(key: string): Promise<T | null>;
  set(key: string, value: T, ttl?: number): Promise<void>;
  delete(key: string): Promise<void>;
}

class MemoryCacheStore<T> implements CacheStore<T> {
  private store = new Map<string, { value: T; expires?: number }>();

  async get(key: string): Promise<T | null> {
    const entry = this.store.get(key);
    if (!entry) return null;
    
    if (entry.expires && entry.expires < Date.now()) {
      await this.delete(key);
      return null;
    }
    
    return entry.value;
  }

  async set(key: string, value: T, ttl?: number): Promise<void> {
    const expires = ttl ? Date.now() + ttl * 1000 : undefined;
    this.store.set(key, { value, expires });
  }

  async delete(key: string): Promise<void> {
    this.store.delete(key);
  }
}

微服务通信的类型化

使用 gRPC 进行类型化的微服务通信:

import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';

const PROTO_PATH = __dirname + '/user.proto';

const packageDefinition = protoLoader.loadSync(PROTO_PATH);
const userProto = grpc.loadPackageDefinition(packageDefinition).user;

interface UserService {
  getUser(call: grpc.ServerUnaryCall<{ id: number }, User>, callback: grpc.sendUnaryData<User>): void;
  createUser(call: grpc.ServerUnaryCall<User, User>, callback: grpc.sendUnaryData<User>): void;
}

const server = new grpc.Server();
server.addService((userProto as any).UserService.service, {
  getUser: (call, callback) => {
    const user = users.find(u => u.id === call.request.id);
    callback(null, user || { id: 0, name: '' });
  },
  createUser: (call, callback) => {
    const newUser = { ...call.request, id: users.length + 1 };
    users.push(newUser);
    callback(null, newUser);
  }
} as UserService);

server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
  server.start();
});

部署与容器化的类型化配置

类型化的 Docker 配置管理:

interface DockerConfig {
  image: string;
  ports: { host: number; container: number }[];
  environment: Record<string, string>;
  volumes?: { host: string; container: string }[];
}

const nodeAppConfig: DockerConfig = {
  image: 'node:16-alpine',
  ports: [{ host: 3000, container: 3000 }],
  environment: {
    NODE_ENV: 'production',
    DATABASE_URL: 'postgres://user:pass@db:5432/db'
  },
  volumes: [
    { host: './dist', container: '/app/dist' },
    { host: './node_modules', container: '/app/node_modules' }
  ]
};

function generateDockerfile(config: DockerConfig): string {
  return `
FROM ${config.image}
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE ${config.ports.map(p => p.container).join(' ')}
CMD ["node", "dist/index.js"]
  `;
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:与Vue集成

下一篇:与Express/Koa框架

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌