You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于aiohttp+jinja2实现Python本地服务处理前端表单数据

完全可以不依赖Django、Flask,基于你选定的aiohttp+jinja2技术栈就能完成前后端表单对接,以下是可直接运行的实现步骤:

1. 安装依赖

执行以下命令安装所需包,不需要额外安装其他重量级Web框架:

pip install aiohttp aiohttp-jinja2

2. 目录结构准备

在工作目录下创建两个对象:

  • 主程序文件app.py
  • 模板文件夹templates,后续调整完成的前端页面就存在这个文件夹里,命名为index.html

3. 前端页面调整

你原有的前端代码需要做三处小修改才能正常对接后端:

  • 给两个输入框加参数标识,方便后端取值
  • 表单提交时阻止默认的页面跳转行为,改用异步请求把用户输入发给后端
  • 拿到后端返回的扫描结果后,动态渲染到页面的消息容器中
    调整后的完整index.html代码如下(原有样式完全保留):
<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>Port Scanner</title>
   <style>
       html {
           font-family: Verdana, "sans-serif";
       }

       body {
           min-height: 100vh;
           background: black no-repeat;
       }

       h1 {
           text-align: center;
           color: white;
           text-shadow: 0 3px 5px rgba(150, 150, 150, 0.8);
       }

       #root {
           display: flex;
           flex-direction: column;
           align-items: center;
       }

       #messages {
           width: 70%;
       }

       .message {
           background-color: white;
           width: 100%;
           padding: 20px;
           border-radius: 10px;
           -webkit-transition: 0.3s;
           -moz-transition: 0.3s;
           transition: 0.3s;
           -webkit-box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
           -moz-box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
           box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
           box-sizing: border-box;
           margin-bottom: 10px;
       }

       .message:hover {
           -webkit-transition: 0.3s;
           -moz-transition: 0.3s;
           transition: 0.3s;
           -webkit-box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
           -moz-box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
           box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
       }

       .message__created {
           font-size: 12px;
           color: darkgrey;
           text-align: right;
       }

       .message__text {
           font-size: 20px;
           color: black;
           margin-top: 5px;
       }

       .message__ratings {
           display: flex;
           justify-content: space-between;
           font-size: 16px;
           font-weight: 400;
           margin-top: 5px;
       }

       .form {
           width: 70%;
           margin-bottom: 20px;

           display: flex;
           flex-direction: column;
           gap: 60px;
       }

       .form__button {
           text-align: center;
           margin-top: 150px;
           background-color: white;
           cursor: pointer;
       }

       .form__input, .form__button {
           box-sizing: border-box;
           width: 100%;
           font-size: 18px;
           outline: none;
           border: none;
           padding: 20px;
           border-radius: 15px;
           -webkit-transition: 0.3s;
           -moz-transition: 0.3s;
           transition: 0.3s;
           -webkit-box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
           -moz-box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
           box-shadow: 0px 5px 5px 0px rgba(0, 0, 0, 0.1);
       }

       .form__input:focus, .form__button:hover {
           -webkit-transition: 0.3s;
           -moz-transition: 0.3s;
           transition: 0.3s;
           -webkit-box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
           -moz-box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
           box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.5);
       }
   </style>
</head>
<body>
<div>
   <h1>Port Scanner</h1>
   <div id="root">
       <form class="form" onsubmit="sendMessage(event)">
           <input id="message_text" name="ip" class="form__input" type="text"
                  placeholder="IP adress" required/>
           <input id="message_text1" name="port_range" class="form__input" type="text"
                  placeholder="Range of ports (eg: 1-1000)" required/>
           <button class="form__button" type="submit">Scan</button>
       </form>
       <div id="messages">

       </div>
   </div>
</div>
</body>
<script type="application/javascript">
   const sendMessage = async (e) => {
       e.preventDefault();
       alert('Please wait for the scanning!');
       const ip = document.getElementById('message_text').value;
       const portRange = document.getElementById('message_text1').value;
       const resp = await fetch('/scan', {
           method: 'POST',
           headers: {
               'Content-Type': 'application/json'
           },
           body: JSON.stringify({ip: ip, port_range: portRange})
       });
       const result = await resp.json();
       const msgContainer = document.getElementById('messages');
       const msgEl = document.createElement('div');
       msgEl.className = 'message';
       let openPortsHtml = result.open_ports.length > 0 ? result.open_ports.join(', ') : 'No open ports';
       msgEl.innerHTML = `
           <div class="message__created">Scan time: ${new Date().toLocaleString()}</div>
           <div class="message__text">Target IP: ${result.ip}</div>
           <div class="message__text">Port range: ${result.port_range}</div>
           <div class="message__text">Open ports: ${openPortsHtml}</div>
       `;
       msgContainer.prepend(msgEl);
       document.getElementById('message_text').value = '';
       document.getElementById('message_text1').value = '';
   }
</script>
</html>

4. 服务端逻辑编写

app.py中实现三个核心模块:aiohttp服务初始化、jinja2模板配置、路由处理(首页返回前端页面、/scan接口接收参数执行扫描返回结果),内置异步端口扫描逻辑,不需要额外依赖第三方扫描库,完整代码如下:

import asyncio
from aiohttp import web
import aiohttp_jinja2
import jinja2

# 异步单端口扫描逻辑
async def scan_port(ip: str, port: int, timeout: float = 1.0):
    try:
        fut = asyncio.open_connection(ip, port)
        reader, writer = await asyncio.wait_for(fut, timeout=timeout)
        writer.close()
        await writer.wait_closed()
        return port
    except:
        return None

# 批量端口扫描
async def run_scan(ip: str, port_range: str) -> list:
    if '-' in port_range:
        start_port, end_port = map(int, port_range.split('-'))
    else:
        start_port = end_port = int(port_range)
    tasks = [scan_port(ip, port) for port in range(start_port, end_port + 1)]
    results = await asyncio.gather(*tasks)
    return sorted([p for p in results if p is not None])

# 首页路由,返回前端页面
@aiohttp_jinja2.template('index.html')
async def index(request):
    return {}

# 扫描接口,处理前端提交的参数
async def scan_handler(request):
    try:
        data = await request.json()
        ip = data.get('ip', '').strip()
        port_range = data.get('port_range', '').strip()
        if not ip or not port_range:
            return web.json_response({'code': 400, 'msg': 'Missing parameters'}, status=400)
        open_ports = await run_scan(ip, port_range)
        return web.json_response({
            'code': 200,
            'ip': ip,
            'port_range': port_range,
            'open_ports': open_ports
        })
    except Exception as e:
        return web.json_response({'code': 500, 'msg': f'Scan error: {str(e)}'}, status=500)

# 初始化应用
def create_app():
    app = web.Application()
    aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
    app.add_routes([
        web.get('/', index),
        web.post('/scan', scan_handler)
    ])
    return app

if __name__ == '__main__':
    app = create_app()
    web.run_app(app, host='127.0.0.1', port=8080)

5. 运行验证

执行命令python app.py启动服务,打开浏览器访问http://127.0.0.1:8080即可使用,输入IP和端口范围点击Scan按钮,等待扫描完成后结果会自动展示在页面上。

提示:端口扫描属于敏感操作,该服务仅建议在本地localhost环境运行,请勿暴露到公网;如果需要提升可用性,可以自行在接口层增加IP格式校验、端口范围合法性校验、扫描频率限制逻辑。

内容的提问来源于stack exchange,提问作者Parcurcik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 19:51:18