☰
用Flask做最简单的服务端接收数据:从零搭建HTTP接口
2026/10/2 3:12:57 网站建设 项目流程

我最早正经写服务端接收数据,是因为要给一组环境传感器做数据上报。当时第一反应是找个现成的后端框架,翻了半天企业级框架的教程,被那一堆配置直接劝退——程序能不能跑起来另说,光理解"为什么一个接收数据的工程需要这么多文件"就够头疼。后来我换了个思路:我其实只需要一个一直运行的程序,监听某个端口,等数据进来,收下来存起来,再给发送方回一句"收到了"。就这点事,不夸张地说,Python标准库就能做到,换Flask写也就三十行代码。

这篇文章就把这套"最简单服务端"从头到尾讲透:服务端接收数据到底接收的是什么、不同场景怎么选方案、代码怎么写、怎么自测,以及我在实际项目里被数据接收坑过的几个点。内容不追求大而全,追求的是你照着做,十分钟内能跑通一个真正能收数据的服务端。适合刚接触前后端联调、在做小项目、搞硬件上报,或者只是临时想验证某个接口的人。

1. 先把"接收数据"这件事拆明白

1.1 我们口中的"接收数据"到底是在接收什么

很多人一听"服务端接收数据",脑子里浮现的是后台管理系统、数据库集群、消息队列这些东西。但实际上,绝大多数场景根本没到那个复杂度。我把遇到过的"接收数据"需求归了下类,基本都是下面几种:

  • 网页表单提交:前端页面填了个表单,点提交,后端要拿到这些字段存下来。
  • App或小程序上报:手机端采集了用户行为、定位、日志,定时往服务端发送。
  • 硬件设备上报:温湿度传感器、GPS追踪器、摄像头状态,通过HTTP接口周期性上报数据。
  • 系统间回调通知:支付平台、短信平台在某个事件发生后,回调你的接口告诉你"订单已支付"。
  • 脚本或爬虫抓取结果:另一个脚本跑完任务后,把结果POST给你。

这些场景有个共同点:都是有一个东西主动把数据发给你运行的程序。你的程序不需要去连接别人,只需要老老实实在一个端口上等着。所以"接收数据"这个动作,本质上就三件事:

  1. 持续监听某个网络端口;
  2. 收到请求后,把请求里的数据解析出来;
  3. 给发送方一个明确的响应。

仅此而已。至于数据库、事务、权限这些,都是收到数据之后的事,不属于"接收"这个动作本身。

1.2 一次请求从发出到被接收,中间发生了什么

为了后面调试方便,这里有必要把链路简单过一遍。你可以把它理解成去餐厅吃饭:

  • 客户端(浏览器、手机、传感器)就是顾客,它知道你的服务端地址(IP加端口),相当于知道饭馆开在哪条街几号。
  • 顾客进门喊"服务员"(发起HTTP请求),这一步走的是你服务端正在监听的端口,比如5000。
  • 你的程序就是服务员,听到喊声后,要看顾客点了什么菜(读取请求里的数据),然后去后厨做(业务处理),最后把菜端上桌(返回响应)。

在这个过程里,几个关键要素要记住:

请求行:POST /receive HTTP/1.1 请求头:Content-Type: application/json (告诉服务端数据是什么格式) 请求体:{"temp": 26.5, "humidity": 60} (真正要接收的数据)

服务端接收数据,做的就是两件事:解析请求头,按格式读请求体。至于"0.0.0.0"这类监听地址、"5000"这种端口号,都是你开启监听时需要先理解的参数——监听地址决定谁能连、端口决定连哪里。

1.3 GET和POST:两种最常见的"递纸条"方式

初学者最容易混淆的就是GET和POST的区别。其实从"服务端接收数据"的角度看,区别非常直观:

方式数据放在哪里常见用途特点
GETURL末尾的查询字符串里,比如?name=abc&value=123查询、调试、参数简单可被浏览器地址栏直接访问,会留在历史记录里
POSTHTTP请求体的body里提交表单、上报JSON数据、文件上传数据不在URL中,可传大容量和复杂结构

举个例子,同样是上报一条温度数据:

GET方式: http://localhost:5000/receive?device=esp32&temp=26.5 POST方式: http://localhost:5000/receive body: {"device": "esp32", "temp": 26.5}

如果你只是自己调试,GET快得多,浏览器里直接打开链接就能触发。但准备正式接收业务数据,我建议一律用POST,原因有三点:数据结构可以复杂一点点、长度不受URL限制、不会因为数据里的特殊字符导致URL解析出错。

提示:根本就不存在所谓的"GET更安全"这种说法。真正的数据保密靠的是HTTPS,而不是靠把数据塞进body里掩耳盗铃。

2. 别一上来就整企业级框架,先选一个"真简单"的方案

2.1 常见方案横向对比

"简单"这两个字,不同背景的人理解不同。一个Java后端朋友觉得Spring Boot已经很简单了,但对一个刚转行、或者只是搞个硬件Demo的人来说,光把Maven依赖拉下来就得折腾半天。我按"从零开始跑通一个接收数据的服务端"需要付出的成本,把常见方案排了个队:

方案依赖启动成本适合场景短板
Python内置http.server零依赖最低,Python自带临时调试、一次性任务要手动解析报文,不适合做业务
Python + Flask需装Flask低,一个pip命令快速原型、小型项目、硬件上报性能上限不如专门的高性能框架
Node.js + Express需装Node依赖低前端顺手、Node环境已有回调风格需要熟悉
Go + 标准库net/http零第三方依赖低要单文件部署、追求性能语法对新手略陌生
Java + Spring Boot重高大型团队、复杂业务很多人就是被它劝退的

你可能会问:既然Python内置的http.server零依赖,为什么不直接用它?因为它把"接收数据"这件事做成了最原始的样子:收到的是一个完整HTTP报文,你要从字符串里手动抠出请求头、body、参数,还得自己处理url解码、JSON解析。写个Demo没问题,做正经功能就是在给自己挖坑。

2.2 为什么我推荐Flask作为起步方案

Flask是一个微框架(Micro Framework),所谓"微",指的是它只解决你递纸条的核心需求:路由、请求解析、响应返回。它不需要你理解"依赖注入""中间件""配置中心"这些花哨的概念。

我用Flask已经很多年,总结它的优势就三条:

  1. 路由写起来像在报菜名。@app.route("/receive", methods=["POST"])底下直接跟处理的函数,一眼就能看懂"哪个路径对应哪段逻辑"。
  2. 请求数据解析是现成的。request.args拿GET参数、request.get_json()拿JSON、request.form拿表单数据,不用自己写解析逻辑。
  3. 返回JSON也方便。直接返回一个dict,Flask自动帮你序列化并加上对应的Content-Type头。

还有一个不太被提及但很现实的好处:Flask的教程、问答、现成代码是Python后端框架里最多的。你遇到任何小问题,比如"Flask接收不到POST的body",搜一下基本就有答案。对于新手或者做快速验证的人来说,这个生态价值比框架本身的性能重要得多。

注意:如果你确实只是想在终端里快速看一眼"某个地址发来的原始请求长什么样",那用http.server反而快。在Python环境里执行python -m http.server 8000,浏览器访问一下,终端会输出请求日志。这个技巧可以用来应急。

3. 三十行代码搭出第一个能收数据的服务端

3.1 环境准备:就两步

先确认Python已经装好,在终端里执行:

python3 --version

看到版本号之后,安装Flask:

pip install flask

国内网络如果下载慢,可以临时换一下Python软件源,但不要为了图快装来路不明的包。

装完验证一下:

python3 -c "import flask; print(flask.__version__)"

没报错就是装好了。

3.2 第一版:把GET参数原样打印出来

创建一个文件server.py,先写个最基础的版本:

from flask import Flask, request app = Flask(__name__) @app.route("/receive", methods=["GET"]) def receive(): name = request.args.get("name", "") value = request.args.get("value", "") print("收到GET请求:", name, value) return "ok" if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)

这段代码要拆开看:

  • app = Flask(__name__)创建了一个Flask应用,后面所有路由都挂在它上。
  • @app.route("/receive", methods=["GET"])声明了路径和方法:只有访问/receive并且是GET,下面的函数才会执行。
  • request.args是所有GET查询参数的集合,request.args.get("name")拿到?name=后面的值。
  • app.run(host="0.0.0.0", port=5000)启动监听,0.0.0.0表示允许局域网内其他设备访问,如果只想本机访问就改成127.0.0.1。

启动:

python3 server.py

然后另开一个终端,用curl模拟发数据:

curl "http://localhost:5000/receive?name=temp&value=26.5"

回到服务端终端,你会看到打印出:

收到GET请求: temp 26.5

到这里,你的服务端已经真正意义上"接收"到了数据。虽然是GET,但骨架已经有了。

3.3 第二版:接收POST JSON数据

实际业务里最常遇到的就是客户端POST一个JSON过来。把代码升级一下,加点容错:

from flask import Flask, request app = Flask(__name__) @app.route("/api/data", methods=["POST"]) def api_data(): # silent=True: 如果body不是合法JSON,不会抛异常,而是返回None data = request.get_json(silent=True) if data is None: return {"code": 1, "message": "JSON解析失败"}, 400 print("收到JSON数据:", data) return {"code": 0, "message": "ok", "received": data} if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)

这次的改动要点:

  • request.get_json(silent=True)直接解析请求体里的JSON。silent=True这一步很重要——如果客户端发了个"我不是JSON"的东西过来,框架会抛一个400错误,但直接用它会在调试时看到一屏幕堆栈。你更希望的是拿到一个None,然后自己决定怎么回复。
  • 返回的是字典,Flask会自动把它变成JSON字符串,还会自动设置Content-Type: application/json。
  • 返回400状态码,语义上告诉客户端"你发的东西不合规范"。

测试命令:

curl -X POST \ -H "Content-Type: application/json" \ -d '{"device":"esp32","temp":26.5,"humidity":60}' \ http://localhost:5000/api/data

服务端打印:

收到JSON数据: {'device': 'esp32', 'temp': 26.5, 'humidity': 60}

curl返回:

{"code":0,"message":"ok","received":{"device":"esp32","temp":26.5,"humidity":60}}

3.4 第三版:一个统一入口,GET、POST、JSON、表单全接住

真实的接收场景往往没有你想的那么规范。有可能前端一会儿用JSON,一会儿用表单;也有可能是你临时给别的部门同学调试,对方习惯用GET带参数。我的做法是做一个"通用接收器",不管什么格式先接住,把内容打印出来并原样返回:

from flask import Flask, request app = Flask(__name__) @app.route("/receive", methods=["GET", "POST"]) def receive_all(): # 记录请求方法 method = request.method # 1. GET查询参数,比如 /receive?a=1&b=2 query_params = dict(request.args) # 2. 判断Content-Type,决定怎么解析body content_type = request.headers.get("Content-Type", "") body_data = None if "application/json" in content_type: body_data = request.get_json(silent=True) elif "application/x-www-form-urlencoded" in content_type: body_data = dict(request.form) else: # 其他类型,先按原文读出来 body_data = request.get_data(as_text=True) print(f"[{method}] 查询参数: {query_params}") print(f"[{method}] body内容: {body_data}") return { "method": method, "query_params": query_params, "body": body_data, "status": "received" } if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True)

这个版本好在哪?它把"接收"和"业务处理"解耦了。不管你收到什么,先把内容记录清楚,调试的时候一目了然。后面想接数据库也好、转发给别的服务也好,都是在拿到body_data之后再加逻辑。

提示:request.get_data(as_text=True)是最后的兜底方案,它把原始body当字符串读出来。碰到文件上传时这个不适用,文件要用request.files,这点后面单独说。

4. 数据收到之后,拿它干什么

4.1 别用print,改用日志

我最早偷懒直接print,结果服务端跑了一晚上,第二天想查昨晚哪些设备上报了数据,终端翻半天全被滚动刷没了。你要记住:print 是给调试用的,日志是给运行用的。

先用Python自带的logging模块把日志写到文件里:

import logging from logging.handlers import RotatingFileHandler # 配置:日志按大小轮转,单个文件超过1MB自动切分 handler = RotatingFileHandler("server.log", maxBytes=1024*1024, backupCount=5) formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) logger = logging.getLogger("my_server") logger.setLevel(logging.INFO) logger.addHandler(handler)

然后在接收函数里把原来的print替换成:

logger.info(f"收到请求: {method} 查询参数: {query_params} body: {body_data}")

这样数据接收完,服务端程序爱怎么重启都没事,日志文件里什么都在。

4.2 把数据存进SQLite,不用装任何数据库

很多时候接收完数据是要落库的。对小型项目、个人工具、硬件上报这类场景,我强烈推荐直接用Python标准库自带的SQLite——不用装MySQL,不用配置连接信息,一个文件就是一个数据库。

接收数据并存库的完整示例:

import sqlite3 import json from datetime import datetime from flask import Flask, request app = Flask(__name__) def init_db(): conn = sqlite3.connect("data.db") conn.execute(""" CREATE TABLE IF NOT EXISTS sensor_data ( id INTEGER PRIMARY KEY AUTOINCREMENT, device TEXT, temp REAL, humidity REAL, raw TEXT, created_at TEXT ) """) conn.commit() conn.close() @app.route("/api/data", methods=["POST"]) def api_data(): data = request.get_json(silent=True) if data is None: return {"code": 1, "message": "JSON解析失败"}, 400 conn = sqlite3.connect("data.db") conn.execute( "INSERT INTO sensor_data (device, temp, humidity, raw, created_at) VALUES (?, ?, ?, ?, ?)", ( data.get("device", ""), data.get("temp", 0), data.get("humidity", 0), json.dumps(data, ensure_ascii=False), datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) ) conn.commit() conn.close() return {"code": 0, "message": "ok", "id": "已入库"} if __name__ == "__main__": init_db() app.run(host="0.0.0.0", port=5000, debug=True)

这段代码把"接收"和"存储"串在了一起:先解析JSON,再插入SQLite表,最后返回成功响应。SQLite单文件、无需运维,特别适合"先跑起来再考虑扩展"的阶段。

4.3 收到数据后要"回话",学会用HTTP状态码

很多初学的人有个坏习惯:服务端收到数据后不管什么情况都返回200。这会让发送方误以为"数据一定处理成功了",到头来数据丢了都不知道在哪丢的。

我的建议是最少区分三种响应:

情况状态码响应体示例发送方应该怎么做
接收成功,处理成功200{"code":0, "message":"ok"}不要重发
格式错误或参数不对400{"code":1, "message":"设备ID不能为空"}检查代码,修正后重发
服务端内部出错500{"code":2, "message":"数据库写入失败"}等一会重试,或报障碍

尤其要注意400和500的区别。我遇到过很多硬件项目,设备端只会收到非200就重发,结果因为服务端代码有个字段没判断,导致设备疯狂重发,把日志刷爆。正确做法是服务端自己把参数校验做好,校验不通过明确返回400,让发送方知道"不要再盲目重试,先去改配置"。

4.4 文件上传怎么接收

接收数据不只是JSON,偶尔还要接收文件,比如设备拍的照片、App上传的日志压缩包。Flask处理这个也很直接:

from flask import Flask, request import os app = Flask(__name__) UPLOAD_FOLDER = "uploads" os.makedirs(UPLOAD_FOLDER, exist_ok=True) @app.route("/upload", methods=["POST"]) def upload_file(): if "file" not in request.files: return {"code": 1, "message": "缺少file字段"}, 400 file = request.files["file"] # file.filename是原始文件名,使用时严格注意:别直接用用户给的路径 safe_name = os.path.basename(file.filename or "unnamed") save_path = os.path.join(UPLOAD_FOLDER, safe_name) file.save(save_path) return {"code": 0, "message": "文件已保存", "path": save_path}

注意我用os.path.basename把文件名取了一遍——这是安全习惯,防止用户传一个包含../../的路径把你的服务器目录穿透。无论接收文件还是JSON,凡是用户输入,都要假设它是恶意的。

5. 实测:用各种方式把数据"砸"向你的服务端

5.1 curl:最快的自测方式

启动服务端后,我调试接口默认先上curl,因为不需要打开任何图形界面,一条命令完事:

# 发GET带参数 curl "http://localhost:5000/receive?name=temp&value=26.5" # 发POST JSON(Linux/macOS的bash环境) curl -X POST -H "Content-Type: application/json" \ -d '{"device":"esp32","temp":26.5}' \ http://localhost:5000/api/data # 如果是在Windows的cmd里,最外面的引号要改成双引号,JSON里用单引号转义 # curl -X POST -H "Content-Type: application/json" -d "{\"device\":\"esp32\",\"temp\":26.5}" http://localhost:5000/api/data

curl的关键参数就三个:-X指定方法、-H指定请求头、-d指定body。只要这条命令能通,说明服务端接收链路基本没问题。

5.2 图形化工具:Postman、Apifox或Apipost

如果你觉得命令行不直观,或者要调试的字段很多,可以用图形化的接口请求工具。不管哪个,配置方式都一样:

  1. 选择请求方法(POST);
  2. 输入请求地址,比如http://192.168.1.100:5000/api/data;
  3. 在Headers里加Content-Type: application/json(JSON格式选择后很多工具会自动加);
  4. 在Body里选raw,格式选JSON,填上要发送的数据;
  5. 点击发送,看返回结果。

这类工具最大的价值是可以把一组请求参数保存下来,下次直接复用。做接口测试、给别人演示接口怎么用都方便。我平时会在项目目录里保留一份导出的接口集合,传给协作的硬件工程师,对方打开就能调试,省得来回要参数格式。

5.3 在代码里模拟客户端:给硬件端或前端看的示例

如果你是那个需要对接别人服务端的人,可以用脚本快速把测试请求发出来。Python的requests库最直白:

import requests url = "http://localhost:5000/api/data" data = { "device": "esp32-001", "temp": 26.5, "humidity": 60, "timestamp": "2024-01-01 12:00:00" } resp = requests.post(url, json=data, timeout=5) print(resp.status_code) print(resp.json())

我一般建议用json关键字参数而不是data+手动指定Header,因为requests会在传dict给json时自动帮你序列化并设置Content-Type: application/json,少一步手动操作就少一处出错的可能。

如果是浏览器端JavaScript要发数据,最简写法是:

fetch("http://localhost:5000/api/data", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ device: "web", temp: 22.5 }) }) .then(resp => resp.json()) .then(json => console.log(json));

把服务端跑起来,再用上面任意一种方式发数据,看到服务端成功打印、返回正常响应,整个"接收数据"的闭环就通了。

6. 踩坑实录:我接收数据时掉过的五个坑

6.1 中文乱码:要么是发送方没告诉你怎么编码,要么是终端在骗你

现象是服务端打印出来的Json里有中文的地方全变成\u4f60\u597d或者乱码。排查链路是这样的:

第一步,先确认服务端收到的原始字节是什么。在接收函数里临时加一行:

print(repr(request.get_data()))

看字节流里是不是合法的UTF-8。如果原始字节就是\\u4f60\\u597d这种转义形式,那其实是好的——JSON规范允许这种写法,只是Python打印时默认显示转义,不代表乱码。想要显示中文,在打印前加:

print(json.dumps(data, ensure_ascii=False, indent=2))

第二步,如果原始字节真的是乱码,说明发送方没有按UTF-8编码。这时需要对方在请求头里显式指定Content-Type: application/json; charset=utf-8,或者严格使用标准的JSON库发送数据。

第三步,还有一个常常被忽略的:终端编码。Windows的cmd默认可能是GBK,服务端程序输出UTF-8的中文到了终端里就会显示乱码。这时不是数据错了,是显示错了。可以在终端执行chcp 65001切到UTF-8再跑。

6.2 浏览器跨域被拦:curl没问题,前端用的fetch却报CORS错误

这个坑几乎是每个做前后端分离的人都会遇到的:服务端curl测得好好的,前端一调用就报blocked by CORS policy。

原因是浏览器的安全策略:只有同协议、同域名、同端口的页面才允许访问你的接口。你的前端跑在http://localhost:5173,服务端跑在http://localhost:5000,端口不同,就算"跨域"。

排查链路:

  1. 确认报错是否来自浏览器控制台——如果你用手机App、curl、requests发数据都没问题,基本可以判定就是跨域问题;
  2. 在服务端加CORS支持,最简单的方式是装Flask的扩展:
pip install flask-cors

然后在代码初始化的时候加一行:

from flask_cors import CORS CORS(app)

CORS(app)默认允许所有来源访问,开发调试够用。生产环境要收紧的话,可以指定origins=["http://your-frontend-domain.com"]。

  1. 如果是生产环境不想引入额外依赖,也可以自己写一个after_request钩子,给所有响应都加上Access-Control-Allow-Origin头。但既然Flask-Cors是官方维护的扩展,直接用扩展是最省事的。

注意:CORS是浏览器的行为,不是服务端的强制限制。加了CORS头不代表任何人都能跨域访问你的接口,服务端该做的鉴权和校验不能省。

6.3 端口被占用:Error: Address already in use

现象很明确:启动服务时直接报OSError: [Errno 98] Address already in use或 Windows 下类似提示。原因不外乎三种:

  • 端口被上一个没关干净的进程占用;
  • 有其他程序恰好用了这个端口;
  • 服务端自己把自己"重复启动"了,因为Flask的debug模式在某些编辑器里会启动两个进程。

排查命令,Linux/macOS:

lsof -i :5000

Windows:

netstat -ano | findstr :5000

找到占用端口的进程ID后,按需杀进程或换端口。我个人更建议调试时固定一个唯一端口,比如 5000;到了部署阶段服务数量多了容易撞,再统一规划。

另外提醒一点:Flask的debug模式会启动一个额外的reloader进程,你改了代码它会自动重启服务。如果这个reloader没被正确回收,可能出现"我明明改了代码,但访问的还是老版本"的情况。排查时用ps看一下有没有多个python进程,有的话全部终止再重新启动。

6.4 数据收到了但不完整:body只有一半

现象是服务端拿到的JSON缺少后半截,解析直接失败。这种情况我在对接某些定制化硬件时遇到过几次,多数原因出在客户端:

  • 要么没有设置正确的Content-Length头;
  • 要么是采用流式(chunked)传输,但发送方没有按规范结束;
  • 要么是超时设置太短,body还没发完连接就被掐断了。

排查链路:

  1. 在服务端用request.get_data(cache=True)拿原始body,看实际长度;
  2. 对比请求头里客户端声明的Content-Length,不一致就是客户端的问题;
  3. 如果确认是客户端流式发送,服务端可以设置app.config["MAX_CONTENT_LENGTH"]定义上限,超过就直接拒绝,避免收不完整还硬解析。

Flask里设置请求体大小上限的写法:

app.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 # 限制1MB

超过这个大小的请求,Flask会直接返回413,发送方就知道自己发的东西超过限制了,而不是收到一个模糊的解析失败。

6.5 服务端一收到"脏数据"就崩

最常见的崩溃是KeyError或TypeError或者body解析出错。比如客户端该传temp字段,结果没传,你代码里直接data["temp"]就会抛异常,返回一个500和一堆堆栈。

解决思路很简单,分三步:

  1. 取值用.get()并给默认值,不要用[]下标方式;
  2. 将解析和业务处理包在 try-except 里,捕获异常后返回结构化错误信息;
  3. 在日志中记录原始body,这样哪怕出了错,也能从日志里看到"当时到底收到了什么"。

改造后的接收函数:

@app.route("/api/data", methods=["POST"]) def api_data(): raw = request.get_data(as_text=True) data = request.get_json(silent=True) if data is None: logger.warning(f"JSON解析失败, 原始数据: {raw}") return {"code": 1, "message": "JSON解析失败"}, 400 try: device = data.get("device", "unknown") temp = float(data.get("temp", 0)) except ValueError: logger.warning(f"字段类型错误, 原始数据: {raw}") return {"code": 2, "message": "temp必须是数字"}, 400 # 继续业务处理... return {"code": 0, "message": "ok", "device": device, "temp": temp}

这套写法保证了两件事:任何异常情况下客户端拿到的都是能看懂的错误信息;服务端不会因为一条脏数据就整个挂掉。

7. 从"能接收"到"像一个正经服务端"

7.1 关闭debug模式,明确绑定地址

debug=True在开发阶段很好用,能实时重载代码、显示详细报错。但也意味着:任何人访问你的地址触发了一个未捕获的异常,都能看到一个包含源码片段和堆栈的调试页面,这在生产环境就是信息泄露。

启动时把它关掉:

if __name__ == "__main__": # 生产环境不要开debug app.run(host="0.0.0.0", port=5000, debug=False)

关于host="0.0.0.0",它的含义是监听所有网卡上的请求。部署在服务器上时,这样写才能让局域网或公网访问到。但如果只是在你自己电脑上调试,建议用127.0.0.1,别把服务暴露给局域网里的其他设备。

7.2 让服务端在后台常驻运行

用python3 server.py启动服务,一旦关闭终端服务就跟着停了。临时跑个Demo无所谓,但如果你要它长期收数据,需要让它脱离终端运行。

Linux服务器上最简单的做法:

nohup python3 server.py > server.log 2>&1 &

这样启动后,关掉SSH会话服务还在跑。不过更规范、也推荐的做法是交给systemd管理,这样服务崩溃了能自动重启、开机自启也方便。写一个服务单元文件,比如/etc/systemd/system/my-server.service:

[Unit] Description=My Data Receiver [Service] ExecStart=/usr/bin/python3 /path/to/server.py Restart=always User=your_user [Install] WantedBy=multi-user.target

然后:

sudo systemctl daemon-reload sudo systemctl start my-server sudo systemctl enable my-server

在开发环境不想管systemd的可以直接用上面的nohup方案。至于生产环境要不要引入gunicorn这类WSGI服务器,这个要看流量和需求。如果只是每秒接收几次上报,Flask自带的服务器完全够用;真要扛高并发再考虑上gunicorn,可以做进程多开。

7.3 下一步还能怎么扩展

"接收数据"只是第一步,链路往后延伸的空间很大。根据我自己的经验,按优先级排列:

  1. 加校验和鉴权:至少用一个请求头里的Token来识别发送方是不是你自己。设备上报场景更要注意,别让任何人POST点假数据就把你的库写满。
  2. 数据转发:接收端可以再作为一个客户端,把数据推给消息队列、其他内部服务,配合第三方队列库或一个简单的HTTP转发就能做。
  3. 接口文档:给别人对接的时候,一份说明清楚"路径、方法、请求头、body格式、返回格式"的文档能省很多沟通成本。先写个最少三行的README,说明用POST还是GET、JSON字段叫什么,就比让对方猜强得多。
  4. 健康检查接口:加一个/ping返回pong,方便别人确认你的服务还活着。负载均衡和监控脚本都会用到这个。

我个人的体会是:接收数据这个功能,90%的项目根本不需要一开始就用企业级框架。一个Flask应用、一张表、一个日志文件,足够对付绝大多数中小型需求。真正要去琢磨架构和高性能的时候,说明你的服务每天收到的数据量已经大到需要认真对待了——到那个阶段再迁移,成本完全可控,因为接收数据的逻辑本来就该保持简单。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询