海南大学交友平台开发实战day7(实现核心匹配算法+解决JSON请求报错问题)

海南大学交友平台开发实战day7(实现核心匹配算法+解决JSON请求报错问题)

大家好,欢迎来到海南大学交友平台开发实战系列的第七天!在前六天的开发中,我们已经完成了登录页、注册页的UI布局、Flask后端基础搭建、数据库初始化及核心表结构创建,打通了前端与后端的基础通信链路。今天的核心任务有两个:一是实现平台核心的匹配算法,完成虚拟测试用户创建、内存过滤机制及/api/match接口开发;二是定位并解决前端点击匹配按钮时,JSON请求无法传递user_id、后端解析失败的400报错问题,全程实战落地,记录每一个踩坑细节和解决思路,帮助大家避开同类问题,高效完成开发。

本博文采用"前端HTML/JS + 后端Python Flask + 数据库SQLite"的技术栈,全程实战落地,包含关键代码、报错分析、修复步骤及功能验证,欢迎大家在评论区交流探讨开发过程中遇到的问题。

一、今日开发核心目标

明确今日开发重点,聚焦核心需求,避免开发偏离方向,具体目标如下:

  1. 后端实现核心匹配算法:按照"基础分50分+同年级(模拟同校区)50分+兴趣10分/个(封顶50分)"的规则,计算用户匹配度,仅推荐匹配度≥80%的用户;

  2. 后端实现内存过滤机制:对匹配失败的用户打exclude标签,本次会话内不再重复匹配,节省算力;

  3. 后端创建虚拟测试用户,用于匹配功能测试,固定测试用户信息,确保测试场景可复现;

  4. 后端开发/api/match接口,接收前端传递的JSON格式user_id,执行匹配逻辑并返回规范结果;

  5. 前端实现匹配按钮交互、匹配名片展示、交友按钮及继续匹配功能,确保与后端接口正常联动;

  6. 定位并解决核心报错:前端点击匹配按钮时,JSON请求未传递user_id,导致后端解析失败,出现400 Bad Request错误。

二、前期准备与核心概念梳理

在开始开发前,先明确本次涉及的核心概念和前期准备,帮助大家快速理解开发逻辑,避免因概念模糊导致的开发误区,同时验证关键函数是否已正确定义,确保开发顺利推进。

2.1 核心概念解析

  • JSON数据传输:前后端数据交互的轻量级格式,前端发送POST请求时,需设置请求头Content-Type: application/json,并将请求体转为JSON字符串,否则后端无法解析,会报400错误;

  • 匹配算法:本次核心算法规则------基础分50分,同年级(模拟同校区)加50分,每有一个相同兴趣加10分,兴趣加分最高50分(总分封顶100分),仅匹配度≥80%的用户会被推荐;

  • 内存过滤机制:通过全局字典存储已排除的用户ID,仅在当前服务会话内有效,重启服务后清空,避免重复匹配失败用户,提升匹配效率;

  • sessionStorage:前端存储用户信息的临时存储方式,用于保存登录后的student_id,供匹配请求时调用,页面关闭后数据清空。

2.2 前期验证:关键函数是否就绪

开发前,先通过Bash命令验证后端、前端的核心函数是否已正确定义,避免开发过程中出现"函数未找到"的问题,验证过程及结果如下:

2.2.1 验证后端关键函数(app.py

执行Bash命令,查询匹配相关核心函数是否存在:

bash 复制代码
grep -n "def calculate_match_score\|def match_user\|match_exclude_cache\|create_test_user" app.py

输出结果(验证成功):

bash 复制代码
142:        create_test_user()
149:match_exclude_cache = {}
153:    return match_exclude_cache.get(student_id, set())
157:    if student_id not in match_exclude_cache:
158:        match_exclude_cache[student_id] = set()
159:    match_exclude_cache[student_id].add(exclude_student_id)
161:def create_test_user():
206:def calculate_match_score(current_user, target_user):
461:def match_user():

结论:后端核心函数(匹配算法、内存过滤、虚拟用户创建、匹配接口)均已正确定义,可正常开展开发。

2.2.2 验证前端关键函数(home.html)

执行Bash命令,查询前端匹配相关交互函数是否存在:

bash 复制代码
grep -n "startMatching\|displayMatchResult\|sendFriendRequest\|continueMatching" home.html

输出结果(验证成功):

bash 复制代码
1153:                    <button class="match-button" id="matchBtn" onclick="startMatching()">
1191:                        <button class="add-friend-btn" id="addFriendBtn" onclick="sendFriendRequest()">
1194:                        <button class="close-card-btn" onclick="continueMatching()">
1704:        async function startMatching() {
1734:                    displayMatchResult(result.data);
1755:        function displayMatchResult(data) {
1788:        function continueMatching() {
1797:                startMatching();
1809:        async function sendFriendRequest() {

结论:前端核心交互函数(匹配触发、结果展示、交友申请、继续匹配)均已定义,可正常对接后端接口。

三、核心功能开发过程(含踩坑与报错修复)

本次开发按"后端功能实现→前端交互实现→报错定位→报错修复→功能验证"的顺序推进,重点记录匹配算法实现和JSON请求报错的解决过程,所有代码可直接复制使用,踩坑细节全程同步。

3.1 后端功能实现(app.py

后端核心实现匹配算法、内存过滤、虚拟测试用户创建及/api/match接口,逐步推进,确保每一步功能可验证。

3.1.1 实现内存过滤机制(match_exclude_cache)

核心需求:匹配失败的用户,在本次会话内不再重复匹配,通过全局字典存储已排除用户ID,仅内存存储,重启服务后清空。

实现代码(可直接复制):

python 复制代码
# 全局内存缓存,存储已排除的用户,格式:{当前用户student_id: {已排除用户student_id集合}}
match_exclude_cache = {}

# 获取当前用户的已排除用户列表
def get_excluded_users(student_id):
    return match_exclude_cache.get(student_id, set())

# 新增排除用户(匹配失败时调用)
def add_excluded_user(student_id, exclude_student_id):
    if student_id not in match_exclude_cache:
        match_exclude_cache[student_id] = set()
    match_exclude_cache[student_id].add(exclude_student_id)
3.1.2 创建虚拟测试用户(create_test_user)

核心需求:创建固定虚拟用户,用于匹配功能测试,固定学号、密码、兴趣及年级,确保测试场景可复现。

实现代码(可直接复制):

python 复制代码
def create_test_user():
    # 检查虚拟用户是否已存在,避免重复创建
    test_user = User.query.filter_by(student_id='20230010001').first()
    if not test_user:
        # 加密存储密码,密码:123456
        hashed_password = generate_password_hash('123456')
        # 虚拟用户信息:学号20230010001,兴趣游泳、PUBG、三角洲行动,年级2024级
        test_user = User(
            student_id='20230010001',
            password=hashed_password,
            nickname='李明',
            grade='2024',
            hobbies='游泳,PUBG,三角洲行动',
            campus='主校区'
        )
        db.session.add(test_user)
        db.session.commit()

# 项目启动时自动创建虚拟测试用户
create_test_user()
3.1.3 实现核心匹配算法(calculate_match_score)

核心需求:按规则计算用户匹配度,基础分50分,同年级加50分,每有一个相同兴趣加10分,封顶50分,返回匹配度和共同兴趣。

实现代码(可直接复制):

python 复制代码
def calculate_match_score(current_user, target_user):
    # 基础分50分
    score = 50
    # 同年级(模拟同校区)加50分
    if current_user.grade == target_user.grade:
        score += 50
    # 计算共同兴趣,每一个加10分,封顶50分
    # 将兴趣字符串转为集合,便于计算交集
    current_hobbies = set(current_user.hobbies.split(',')) if current_user.hobbies else set()
    target_hobbies = set(target_user.hobbies.split(',')) if target_user.hobbies else set()
    common_hobbies = list(current_hobbies & target_hobbies)
    # 兴趣加分,最多50分
    hobby_score = len(common_hobbies) * 10
    score += min(hobby_score, 50)
    # 返回匹配度(百分比)和共同兴趣
    return {
        'percent': score,
        'common_hobbies': common_hobbies
    }
3.1.4 开发/api/match接口(match_user函数)

核心需求:接收前端传递的JSON格式user_id,执行匹配逻辑,返回匹配成功的用户信息和匹配度,接口返回格式固定。

初始实现代码(存在隐藏问题,后续报错根源):

python 复制代码
@app.route('/api/match', methods=['POST'])
@login_required
def match_user():
    try:
        # 初始问题:仅从session获取student_id,未接收前端传递的user_id
        data = request.get_json() or {}
        current_student_id = session['student_id']

        # 获取当前用户信息
        current_user = User.query.filter_by(student_id=current_student_id).first()
        if not current_user:
            return api_response(404, '当前用户不存在')

        # 获取已排除的用户列表,排除自己
        excluded_ids = get_excluded_users(current_student_id)
        excluded_ids.add(current_student_id)

        # 获取所有未排除的用户
        all_users = User.query.filter(User.student_id.notin_(list(excluded_ids))).all()
        if not all_users:
            return api_response(404, '暂时没有可匹配的用户,请稍后再试')

        # 随机打乱用户顺序,模拟随机匹配
        import random
        random.shuffle(all_users)

        # 遍历寻找匹配度≥80%的用户
        matched_user = None
        match_result = None
        for target_user in all_users:
            match_result = calculate_match_score(current_user, target_user)
            if match_result['percent'] >= 80:
                matched_user = target_user
                break
            else:
                # 匹配失败,添加到排除列表
                add_excluded_user(current_student_id, target_user.student_id)

        if not matched_user:
            return api_response(404, '暂时没有可匹配的用户,请稍后再试')

        # 构造返回数据,适配前端渲染
        return api_response(200, '匹配成功', {
            'user': {
                'display_name': f"{matched_user.nickname[0]}同学",
                'grade': f"{int(matched_user.grade)-2024+2}年级" if matched_user.grade else '未知年级',
                'campus': matched_user.campus
            },
            'match': match_result
        })
    except Exception as e:
        return api_response(500, f'匹配失败:{str(e)}')

3.2 前端交互实现(home.html)

前端核心实现匹配按钮点击交互、匹配名片展示、交友按钮及继续匹配功能,重点对接后端/api/match接口,传递JSON格式user_id。

3.2.1 匹配名片UI实现(毛玻璃风格)

核心需求:匹配成功后弹出毛玻璃风格名片,圆角24px,展示匹配度、用户姓名、年级、共同兴趣,包含交友按钮和继续匹配按钮,贴合项目整体UI风格。

实现代码(可直接复制):

html 复制代码
<!-- 匹配名片弹窗(毛玻璃风格) -->
<div class="match-card" id="userCard" style="display: none;">
    <div class="match-percent" id="matchPercent">90%</div>
    <div class="user-info">
        <h3 id="userName">李同学</h3>
        <p id="userGrade">大二</p>
    </div>
    <div class="common-hobbies" id="commonHobbies">
        <span class="hobby-tag">游泳</span>
        <span class="hobby-tag">PUBG</span>
    </div>
    <div class="btn-group">
        <button class="add-friend-btn" id="addFriendBtn" onclick="sendFriendRequest()">🤝 交友</button>
        <button class="close-card-btn" onclick="continueMatching()">继续匹配</button>
    </div>
</div>

<style>
/* 毛玻璃风格名片 */
.match-card {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 320px;
    padding: 24px;
    border-radius: 24px;
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(10px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
    color: #333;
    z-index: 999;
}
/* 匹配度徽章 */
.match-percent {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 60px;
    height: 60px;
    border-radius: 50%;
    background: linear-gradient(135deg, #66ccff, #9966ff);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    font-weight: bold;
    animation: gradient 2s infinite;
}
/* 交友按钮样式 */
.add-friend-btn {
    width: 120px;
    height: 40px;
    border: none;
    border-radius: 20px;
    background: linear-gradient(135deg, #66ccff, #9966ff);
    color: #fff;
    font-size: 16px;
    cursor: pointer;
    transition: all 0.3s ease;
}
.add-friend-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(102, 204, 255, 0.5);
}
</style>
3.2.2 匹配按钮交互实现(startMatching函数)

核心需求:点击"开始匹配"按钮,显示"匹配中..."旋转状态,发送JSON格式user_id到后端/api/match接口,接收返回结果并渲染名片。

初始实现代码(核心报错代码):

javascript 复制代码
async function startMatching() {
    const btn = document.getElementById('matchBtn');
    const hint = document.getElementById('matchHint');
    const card = document.getElementById('userCard');

    // 按钮点击动画
    btn.style.transform = 'scale(0.9)';
    setTimeout(() => {
        btn.style.transform = '';
    }, 150);

    // 显示加载状态,禁用按钮防止重复点击
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i><span>匹配中...</span>';

    try {
        // 核心报错点:设置了JSON请求头,但未传递任何请求体(无user_id)
        const response = await fetch(`${API_BASE}/match`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
                // 缺失请求体,未传递user_id
            }
        });
        const result = await response.json();

        if (result.code === 200) {
            // 匹配成功,渲染名片
            displayMatchResult(result.data);
            hint.textContent = '';
        } else {
            hint.textContent = result.msg;
            setTimeout(() => {
                hint.textContent = '';
            }, 3000);
        }
    } catch (error) {
        console.error('匹配请求失败:', error);
        hint.textContent = '匹配失败,请稍后再试';
        setTimeout(() => {
            hint.textContent = '';
        }, 3000);
    } finally {
        // 恢复按钮状态
        btn.disabled = false;
        btn.innerHTML = '开始匹配';
    }
}

3.3 核心报错:JSON请求解析失败(400 Bad Request)

当点击匹配按钮时,前端提示匹配失败,查看后端日志发现报错:400 Bad Request,JSON解析失败。这是本次开发的核心踩坑点,也是今天需要重点解决的问题。

3.3.1 报错原因定位

通过Bash命令查看前端startMatching函数和后端match_user接口,定位报错根源:

  1. 前端问题:设置了Content-Type: application/json请求头,但未传递任何请求体(未发送user_id),导致后端无法解析JSON数据;

  2. 后端问题:check_login接口未返回student_id,前端无法获取并存储到sessionStorage,即使后续传递请求体,也无法获取正确的user_id;同时match_user接口仅从session获取student_id,未兼容前端传递的user_id参数。

3.3.2 报错验证过程(Bash命令)

通过Bash命令查看前端函数和后端接口,确认报错根源:

bash 复制代码
# 查看前端startMatching函数,确认是否传递请求体
grep -A20 "async function startMatching" "d:\science_discover\learn\HUN_friend\HUN_self_build version1.0.3 - 副本\home.html" | head -25

# 查看后端match_user接口,确认是否接收user_id
grep -A30 "def match_user" "d:\science_discover\learn\HUN_friend\HUN_self_build version1.0.3 - 副本\app.py" | head -35

输出结果显示:

  • 前端startMatching函数仅设置了请求头,未传递请求体(无user_id);

  • 后端match_user接口仅从session获取student_id,未接收前端传递的user_id;

  • 后端check_login接口未返回student_id,前端无法获取并存储到sessionStorage。

3.3.3 报错修复步骤(全程可复现)

修复思路:先修复后端接口,确保check_login返回student_id、match_user接口兼容前端传递的user_id;再修复前端,存储student_id到sessionStorage,发送请求时传递JSON格式user_id。

步骤1:修复后端check_login接口(app.py

问题:check_login接口未返回student_id,前端无法获取并存储。

修复代码(新增返回student_id):

python 复制代码
def check_login():
    if 'student_id' in session:
        # 新增返回student_id,供前端存储
        return api_response(200, '已登录', {
            'is_logged_in': True,
            'student_id': session['student_id']
        })
    return api_response(200, '未登录', {'is_logged_in': False})
步骤2:修复后端match_user接口(app.py

问题:仅从session获取student_id,未兼容前端传递的user_id,若前端传递则无法接收。

修复代码(兼容两种获取方式):

python 复制代码
@app.route('/api/match', methods=['POST'])
@login_required
def match_user():
    try:
        data = request.get_json() or {}
        # 兼容前端传递的user_id和session中的student_id
        current_student_id = data.get('user_id') or session['student_id']

        # 后续匹配逻辑不变(省略,与前文一致)
        current_user = User.query.filter_by(student_id=current_student_id).first()
        if not current_user:
            return api_response(404, '当前用户不存在')

        excluded_ids = get_excluded_users(current_student_id)
        excluded_ids.add(current_student_id)
        all_users = User.query.filter(User.student_id.notin_(list(excluded_ids))).all()
        if not all_users:
            return api_response(404, '暂时没有可匹配的用户,请稍后再试')

        import random
        random.shuffle(all_users)

        matched_user = None
        match_result = None
        for target_user in all_users:
            match_result = calculate_match_score(current_user, target_user)
            if match_result['percent'] >= 80:
                matched_user = target_user
                break
            else:
                add_excluded_user(current_student_id, target_user.student_id)

        if not matched_user:
            return api_response(404, '暂时没有可匹配的用户,请稍后再试')

        return api_response(200, '匹配成功', {
            'user': {
                'display_name': f"{matched_user.nickname[0]}同学",
                'grade': f"{int(matched_user.grade)-2024+2}年级" if matched_user.grade else '未知年级',
                'campus': matched_user.campus
            },
            'match': match_result
        })
    except Exception as e:
        return api_response(500, f'匹配失败:{str(e)}')
步骤3:修复前端存储student_id(home.html)

问题:checkLogin和getProfile函数未将student_id存储到sessionStorage,前端无法获取并传递。

修复代码(修改checkLogin和getProfile函数):

javascript 复制代码
// 验证登录状态,存储student_id到sessionStorage
async function checkLogin() {
    try {
        const response = await fetch(`${API_BASE}/check_login`, {
            credentials: 'include'
        });
        const result = await response.json();

        if (result.code === 200 && result.data.is_logged_in) {
            currentUser = result.data;
            // 新增:将student_id存储到sessionStorage
            sessionStorage.setItem('student_id', result.data.student_id);
            return true;
        } else {
            // 未登录,跳转到登录页
            window.location.href = '/login';
            return false;
        }
    } catch (error) {
        console.error('检查登录状态失败:', error);
        return false;
    }
}

// 获取用户资料,补充存储student_id
async function getProfile() {
    try {
        const response = await fetch(`${API_BASE}/get_profile`, {
            credentials: 'include'
        });
        const result = await response.json();

        if (result.code === 200) {
            userProfile = result.data;
            // 新增:将student_id存储到sessionStorage(兜底)
            sessionStorage.setItem('student_id', userProfile.student_id);
        }
    } catch (error) {
        console.error('获取用户资料失败:', error);
    }
}
步骤4:修复前端startMatching函数,传递JSON格式user_id

问题:未传递请求体,未发送user_id,导致后端JSON解析失败。

修复代码(最终可用版):

javascript 复制代码
async function startMatching() {
    const btn = document.getElementById('matchBtn');
    const hint = document.getElementById('matchHint');
    const card = document.getElementById('userCard');

    // 按钮点击动画
    btn.style.transform = 'scale(0.9)';
    setTimeout(() => {
        btn.style.transform = '';
    }, 150);

    // 显示加载状态,禁用按钮
    btn.disabled = true;
    btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i><span>匹配中...</span>';

    try {
        // 核心修复:获取sessionStorage中的student_id,传递JSON格式请求体
        const student_id = sessionStorage.getItem('student_id') || '';
        const response = await fetch(`${API_BASE}/match`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            // 新增请求体,传递JSON格式user_id
            body: JSON.stringify({
                user_id: student_id
            })
        });
        const result = await response.json();

        if (result.code === 200) {
            // 匹配成功,渲染名片
            displayMatchResult(result.data);
            hint.textContent = '';
        } else {
            hint.textContent = result.msg;
            setTimeout(() => {
                hint.textContent = '';
            }, 3000);
        }
    } catch (error) {
        console.error('匹配请求失败:', error);
        hint.textContent = '匹配失败,请稍后再试';
        setTimeout(() => {
            hint.textContent = '';
        }, 3000);
    } finally {
        // 恢复按钮状态
        btn.disabled = false;
        btn.innerHTML = '开始匹配';
    }
}

3.4 其他前端辅助函数实现

补充displayMatchResult(渲染匹配名片)、sendFriendRequest(交友申请)、continueMatching(继续匹配)函数,确保交互完整:

javascript 复制代码
// 渲染匹配结果到名片
function displayMatchResult(data) {
    const card = document.getElementById('userCard');
    const matchPercent = document.getElementById('matchPercent');
    const userName = document.getElementById('userName');
    const userGrade = document.getElementById('userGrade');
    const commonHobbies = document.getElementById('commonHobbies');

    // 填充数据
    matchPercent.textContent = `${data.match.percent}%`;
    userName.textContent = data.user.display_name;
    userGrade.textContent = data.user.grade;
    // 渲染共同兴趣标签
    commonHobbies.innerHTML = '';
    data.match.common_hobbies.forEach(hobby => {
        const tag = document.createElement('span');
        tag.className = 'hobby-tag';
        tag.textContent = hobby;
        commonHobbies.appendChild(tag);
    });
    // 显示名片
    card.style.display = 'block';
}

// 发送交友申请(预留后续接口对接逻辑)
async function sendFriendRequest() {
    const userId = document.getElementById('addFriendBtn').dataset.userId;
    try {
        const response = await fetch(`${API_BASE}/add_friend`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                user_id: sessionStorage.getItem('student_id'),
                target_user_id: userId
            })
        });
        const result = await response.json();
        if (result.code === 200) {
            alert('好友申请已发送,等待对方同意!');
        } else {
            alert(result.msg);
        }
    } catch (error) {
        console.error('发送交友申请失败:', error);
        alert('交友申请发送失败,请稍后再试');
    }
}

// 继续匹配(关闭当前名片,重新触发匹配)
function continueMatching() {
    document.getElementById('userCard').style.display = 'none';
    startMatching();
}

四、功能测试方法与预期结果

修复所有报错后,按以下步骤进行测试,确保匹配功能正常运行,JSON请求无400报错,匹配算法符合规则。

4.1 测试准备

bash 复制代码
# 1. 删除旧数据库(因新增字段,避免数据冲突)
rm instance/hainanu.db

# 2. 启动Flask服务
python app.py

# 3. 登录测试
# 注册新用户:兴趣选择游泳、PUBG、三角洲行动,年级选择2024级
# 或直接使用虚拟测试用户登录:学号20230010001,密码123456

4.2 测试步骤与预期结果(预留空白,供填写最终测试用例)

测试匹配功能(核心测试)

五、今日开发总结与踩坑回顾

今日核心完成了匹配系统的全流程开发和JSON请求报错修复,实现了后端匹配算法、内存过滤、虚拟测试用户创建,以及前端匹配交互和名片渲染,成功解决了"前端JSON请求未传递user_id导致后端400解析失败"的核心问题,同时记录了完整的踩坑细节和修复步骤,为后续开发提供参考。

核心踩坑点回顾:

  1. 前端JSON请求报错:设置了请求头但未传递请求体,导致后端无法解析,修复方案是添加JSON格式的user_id请求体,从sessionStorage获取student_id;

  2. 后端接口兼容问题:仅从session获取student_id,未兼容前端传递的user_id,修复方案是优先获取前端传递的user_id,兜底使用session中的值;

  3. 前端student_id存储问题:checkLogin和getProfile函数未存储student_id到sessionStorage,导致无法获取并传递,修复方案是在两个函数中添加存储逻辑。

今日开发的所有代码均可直接复制使用,匹配功能已实现完整交互,后续可继续完善交友申请的后端逻辑,实现好友列表展示等功能。欢迎大家在评论区交流开发过程中遇到的问题,一起高效避坑、高效开发!

关注我,后续我也会持续更新项目开发进度,分享更多Python前端全栈开发相关的实战经验。

相关推荐
郝学胜-神的一滴2 小时前
[简化版 GAMES 101] 计算机图形学 04:二维变换上
c++·算法·unity·godot·图形渲染·unreal engine·cesium
迷藏4942 小时前
**发散创新:基于角色与属性的混合权限模型在微服务架构中的实战落地**在现代分布式系统中,
java·python·微服务·云原生·架构
下北沢美食家2 小时前
CSS面试题2
前端·css
计算机安禾2 小时前
【数据结构与算法】第41篇:图论(五):拓扑排序与关键路径
c语言·数据结构·c++·算法·图论·visual studio
Q741_1472 小时前
每日一题 力扣 1320. 二指输入的的最小距离 动态规划 C++ 题解
c++·算法·leetcode·动态规划
weixin_461769402 小时前
npm create vue@latest 错误
前端·vue.js·npm
WindrunnerMax2 小时前
从零实现富文本编辑器#13-React非编辑节点的内容渲染
前端·架构·github
四千岁2 小时前
Ollama+OpenWebUI 最佳组合:本地大模型可视化交互方案
前端·javascript·后端
与虾牵手2 小时前
OpenClaw 和 AiPy 怎么选?2026 功能实测对比 + 踩坑全记录
python·ai编程