🎯 第 15 课:实战项目② —— 构建一个“天气查询”API 接口

3 阅读2分钟

太棒了!👏 你已经掌握了服务器、路由、静态资源和异步处理,现在我们来做一个真正像样的项目:


📌 目标
创建一个简单的 RESTful API,接收用户请求的城市名称,返回模拟的天气数据(JSON 格式)。

最终你可以这样使用它:

👉 浏览器访问:

http://localhost:3000/api/weather?city=北京

返回:

{
  "city": "北京",
  "temperature": "26°C",
  "condition": "晴",
  "humidity": "45%"
}

📁 项目结构

我们继续使用之前的项目,只需更新 server.js 即可。

不需要数据库,纯 Node.js 实现 ✅


✅ 第一步:编写服务器代码

// server.js
const http = require('http');
const url = require('url');
const path = require('path');
const fs = require('fs');

// 模拟一些城市的天气数据
const weatherData = {
  北京: { temperature: '26°C', condition: '晴', humidity: '45%' },
  上海: { temperature: '29°C', condition: '多云', humidity: '60%' },
  广州: { temperature: '32°C', condition: '雷阵雨', humidity: '80%' },
  深圳: { temperature: '31°C', condition: '阴', humidity: '75%' },
  杭州: { temperature: '27°C', condition: '小雨', humidity: '70%' }
};

// MIME 类型(用于静态文件)
const mimeTypes = {
  '.html': 'text/html',
  '.css': 'text/css',
  '.js': 'application/javascript',
  '.png': 'image/png'
};

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url, true); // true → 自动解析 query
  const pathname = parsedUrl.pathname;

  // 🌤️ 路由 1:获取天气 API
  if (pathname === '/api/weather' && req.method === 'GET') {
    const city = parsedUrl.query.city;

    if (!city) {
      res.writeHead(400, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: '请提供城市名,例如 ?city=北京' }));
      return;
    }

    const data = weatherData[city];

    if (data) {
      res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
      res.end(
        JSON.stringify({
          city,
          ...data,
          lastUpdated: new Date().toLocaleTimeString()
        })
      );
    } else {
      res.writeHead(404, { 'Content-Type': 'application/json; charset=utf-8' });
      res.end(JSON.stringify({ error: `未找到城市 "${city}" 的天气信息` }));
    }
  }

  // 🖼️ 路由 2:提供前端页面(可选)
  else if (pathname === '/' || pathname.startsWith('/public/')) {
    // 支持首页和静态资源
    const filePath = pathname === '/' 
      ? path.join(__dirname, 'public', 'index.html')
      : path.join(__dirname, 'public', pathname.replace('/public/', ''));

    const extname = path.extname(filePath).toLowerCase();
    const contentType = mimeTypes[extname] || 'application/octet-stream';

    fs.readFile(filePath, (err, content) => {
      if (err) {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('404 - 页面未找到');
      } else {
        res.writeHead(200, { 'Content-Type': contentType + '; charset=utf-8' });
        res.end(content);
      }
    });
  }

  // ❌ 其他路径
  else {
    res.writeHead(404, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ error: 'API 不存在' }));
  }
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(`✅ 天气 API 已启动:http://localhost:${PORT}`);
  console.log(`📍 示例:http://localhost:${PORT}/api/weather?city=北京`);
});

✅ 第二步:测试 API

方法①:直接在浏览器中测试

打开:
👉 http://localhost:3000/api/weather?city=北京

你应该看到类似:

{
  "city": "北京",
  "temperature": "26°C",
  "condition": "晴",
  "humidity": "45%",
  "lastUpdated": "14:32:10"
}

试试其他城市:

  • 上海
  • 广州
  • 输入一个不存在的如 火星 → 会提示 404

方法②:用 HTML 页面调用 API(增强体验)

创建 public/index.html

<!DOCTYPE html>
<html>
<head>
  <title>天气查询</title>
  <style>
    body { font-family: Arial; text-align: center; margin-top: 50px; }
    input, button { padding: 10px; font-size: 1em; }
    .result { margin-top: 20px; font-size: 1.2em; }
  </style>
</head>
<body>
  <h1>🌤️ 天气查询小工具</h1>
  <input type="text" id="cityInput" placeholder="输入城市名" />
  <button onclick="getWeather()">查询</button>
  <div class="result" id="result"></div>
  <script>
    function getWeather() {
      const city = document.getElementById('cityInput').value.trim();
      if (!city) {
        alert('请输入城市名!');
        return;
      }

      // 调用我们的 API
      fetch(`/api/weather?city=${encodeURIComponent(city)}`)
        .then(res => res.json())
        .then(data => {
          if (data.error) {
            document.getElementById('result').innerHTML = `<p style="color:red">${data.error}</p>`;
          } else {
            document.getElementById('result').innerHTML = `
              <h2>${data.city} 的天气</h2>
              <p>🌡️ 温度: ${data.temperature}</p>
              <p>⛅ 状况: ${data.condition}</p>
              <p>💧 湿度: ${data.humidity}</p>
              <p>🕒 更新时间: ${data.lastUpdated}</p>
            `;
          }
        })
        .catch(err => {
          document.getElementById('result').innerHTML = '❌ 请求失败';
        });
    }
  </script>
</body>
</html>

然后重启服务器,访问 http://localhost:3000,就可以输入城市查天气啦!


✅ 学到了什么?

技术点说明
url.parse(req.url, true)解析 URL 和查询参数
/api/weather?city=xxxRESTful 风格 API 设计
res.writeHead(200, {'Content-Type': 'application/json'})返回 JSON 数据
fetch()前端 JavaScript 调用 API
模拟数据快速原型开发的好方法

本课小结一句话

我们用原生 Node.js 实现了一个完整的 API 接口,支持查询参数、JSON 响应、错误处理,并搭配前端页面实现交互,这是现代 Web 开发的核心模式。


📬 下一课预告:
第 16 课:什么是 Express?为什么我们需要框架?

我们将告别“手动造轮子”,引入强大的 Express.js 框架,让开发更高效、代码更清晰!