软件教程 2025年08月6日
0 收藏 0 点赞 668 浏览 5415 个字
摘要 :

文章目录 一、前言 二、useMutation实现 三、Model的构建与使用 四、Restful API介绍 4.1 统一接口 4.2 无状态 4.3 可缓存约束 4.4 分层 4.5 客户端-服务器分离 五、R……




  • 一、前言
  • 二、useMutation实现
  • 三、Model的构建与使用
  • 四、Restful API介绍
    • 4.1 统一接口
    • 4.2 无状态
    • 4.3 可缓存约束
    • 4.4 分层
    • 4.5 客户端-服务器分离
  • 五、Restful API在前端模型层的优势
    • 5.1 专注业务层逻辑
    • 5.2 数据状态管理
    • 5.3 统一的错误处理
    • 5.4 解耦接口层与业务层

    一、前言

    之前在前公司接触到一种很有意思的权限校验接口组合方式,在当时的Vue项目里,所有权限校验接口都是在一个Model对象中,借助修饰器来实现的。我觉得挺有趣,就用React模拟了一下这个实现过程,下面就给大家详细讲讲。深入剖析Restful API前端接口模型架构

    二、useMutation实现

    先给大家看看我模拟出来的React的useMutation钩子函数,这个钩子函数能让代码更好理解。它的代码在utils/useMutation.ts文件里,具体内容如下:

    // utils/useMutation.ts
    
    import { useState } from\'react\';
    
    // 定义useMutation函数,接收一个包含url、method、variables的配置对象
    export function useMutation<T, P>(options: {
    url: string;
    method: \'GET\' | \'POST\' | \'PUT\' | \'DELETE\';
    variables: (params: T) => any;
    }) {
    // 定义loading状态,用于表示请求是否正在进行,初始值为false
    const [loading, setLoading] = useState(false);
    // 定义data状态,用于存储请求返回的数据,初始值为null
    const [data, setData] = useState
    
    (null);
    // 定义error状态,用于存储请求过程中发生的错误,初始值为null
    const [error, setError] = useState(null);
    
    // 定义mutate函数,用于发起请求
    const mutate = async (params: T) => {
    // 请求开始,设置loading为true,清除之前的错误
    setLoading(true);
    setError(null);
    
    // 根据传入的参数生成查询字符串
    const queryParams = new URLSearchParams(options.variables(params)).toString();
    // 根据请求方法拼接url,如果是GET请求,将查询字符串拼接到url后面
    const url = options.method === \'GET\'? `${options.url}?${queryParams}` : options.url;
    
    try {
    // 发起fetch请求
    const response = await fetch(url, {
    method: options.method,
    headers: {
    \'Content-Type\': \'application/json\',
    },
    });
    // 打印响应信息,方便调试
    console.log(\'Response:\', response);
    
    // 如果响应状态码表示成功
    if (response.ok) {
    // 解析响应数据为JSON格式,并存储到data状态中
    const result = await response.json();
    setData(result);
    } else {
    // 如果响应失败,抛出错误
    throw new Error(\'Request failed\');
    }
    } catch (err) {
    // 如果请求过程中发生错误,将错误信息存储到error状态中
    setError(err);
    } finally {
    // 请求结束,设置loading为false
    setLoading(false);
    }
    };
    
    // 返回包含mutate函数、loading状态、data状态和error状态的对象
    return { mutate, loading, data, error };
    }
    

    这里实现的useMutation其实是把从接口定义到函数实现的整个过程都整合到一起了。虽然这么做在一定程度上降低了结耦复用率,不过也让代码更集中处理权限校验接口相关的逻辑。

    三、Model的构建与使用

    接下来看看Model类,我们在这个类里使用useMutation来实现权限校验接口的装饰。代码如下:

    import { useMutation } from \"../utils/useMutation\";
    
    // 定义User数据类型,包含接口返回的各种信息
    interface UserData {
    result: number;
    err_msg: string;
    data: {
    id: number; // 用户ID
    dep: string; // 部门
    Per: string; // 权限
    };
    }
    
    // 定义List数据类型,包含接口返回的列表相关信息
    interface ListData {
    result: number;
    err_msg: string;
    data: Array<{ id: number; name: string; dep: string; Per: string }>;
    }
    
    // 定义Model类,在类的构造函数中初始化请求方法
    export class Model {
    // 初始化用户信息请求方法,传递参数id获取用户数据
    user = useMutation<{ id: number }, UserData>({
    url: \'http://localhost:3000/user\',
    method: \'GET\',
    variables: (p) => ({ id: p.id }),
    });
    
    // 初始化列表信息请求方法,传递分页参数获取列表数据
    list = useMutation<{ page: number, size: number }, ListData>({
    url: \'http://localhost:3000/list\',
    method: \'GET\',
    variables: (p) => ({ page: p.page, size: p.size }),
    });
    }
    

    在这个Model类里,我们挂载了userlist两个属性,分别对应获取用户信息和列表信息的接口。部分类型定义可通通忽略,这里我便在Model身上去挂载了这些属性,打印看看。深入剖析Restful API前端接口模型架构不过,刚定义完的时候,这些属性里的数据都是空的,因为接口还没有真正发起请求,在浏览器的network面板里也看不到请求记录。

    要想让接口发起请求,我们需要在业务层调用它们。这里使用单例模式导出Model对象,这样在全局都能使用同一个对象的属性。下面是业务层的代码示例:

    import React, { useEffect, useState } from\'react\';
    import {useApollo} from \'apllo.js\';
    import { Model } from \'./api/model\';
    
    // 定义一个React组件GameAppModel
    const GameAppModel: React.FC = () => {
    // 使用useApollo获取Model实例
    const model = useApollo(Model);
    
    // 组件挂载时打印model.user和model.list信息
    useEffect(()=>{
    console.log(\'model.user:\', model.user);
    console.log(\'model.list:\', model.list);
    })
    
    // 定义用户数据获取状态和列表数据获取状态
    const [isUserFetched, setIsUserFetched] = useState(false);
    const [isListFetched, setIsListFetched] = useState(false);
    
    // 定义获取用户数据的函数
    const handleFetchUser = async () => {
    // 重置用户数据获取状态
    setIsUserFetched(false);
    // 调用model.user的mutate方法获取用户数据,假设传递用户id为1
    await model.user.mutate({ id: 1 });
    // 设置用户数据获取状态为true
    setIsUserFetched(true);
    };
    
    // 定义获取列表数据的函数
    const handleFetchList = async () => {
    // 重置列表数据获取状态
    setIsListFetched(false);
    // 调用model.list的mutate方法获取列表数据,假设获取第1页,10条数据
    await model.list.mutate({ page: 1, size: 10 });
    // 设置列表数据获取状态为true
    setIsListFetched(true);
    };
    
    // 如果正在获取用户数据或列表数据,显示加载中的提示
    if (model.user.loading || model.list.loading) {
    return
    <div>Loading...</div>
    ;
    }
    
    // 如果获取用户数据或列表数据时发生错误,显示错误提示
    if (model.user.error || model.list.error) {
    return
    <div>Error occurred while fetching data.</div>
    ;
    }
    
    return (
    <div>
    <h2>User Info:</h2>
    {/* 定义获取用户信息的按钮,根据loading状态禁用按钮并显示不同文字 */}
    <button disabled=\"disabled\">
    {model.user.loading? \'Loading User...\' : \'Fetch User Info\'}
    </button>
    {/* 如果已经获取到用户数据,显示数据;否则显示未获取到数据的提示 */}
    {isUserFetched &amp;&amp; model.user.data? (
    <pre>{JSON.stringify(model.user.data, null, 2)}</pre>
    ) : (
    
    No user data fetched
    
    )}
    <h2>Item List:</h2>
    {/* 定义获取列表信息的按钮,根据loading状态禁用按钮并显示不同文字 */}
    <button disabled=\"disabled\">
    {model.list.loading? \'Loading List...\' : \'Fetch Item List\'}
    </button>
    {/* 如果已经获取到列表数据,显示数据;否则显示未获取到数据的提示 */}
    {isListFetched &amp;&amp; model.list.data? (
    <pre>{JSON.stringify(model.list.data, null, 2)}</pre>
    ) : (
    
    No list data fetched
    
    )}
    
    </div>
    );
    };
    
    export default GameAppModel;
    

    增删改我就不再细细演示了,下面讲讲resful API 的介绍以及,优势在哪里为什么要这样去做。深入剖析Restful API前端接口模型架构

    四、Restful API介绍

    讲完了上面的实现过程,下面来聊聊Restful API。REST可不是什么协议或者标准,它其实是一种架构风格。它有几个比较重要的指导原则:

    4.1 统一接口

    常见的像GETPOSTPUTDELETE这些,每个接口都有自己明确的用途,比如GET一般用来获取数据,POST用于创建数据等。

    4.2 无状态

    这就要求客户端给服务器发送的每个请求,都得包含能让服务器理解和完成这个请求的所有必要信息,服务器不会记住客户端之前的请求状态。

    4.3 可缓存约束

    服务器返回的响应得明确告诉客户端这个响应能不能被缓存起来,这样可以提高性能。

    4.4 分层

    系统是分层架构的,每个组件只能看到和它直接交互的那一层,不能跨层访问,这样可以降低系统的复杂度。

    4.5 客户端-服务器分离

    现在大多数项目都是前后端分离的,前端负责展示和用户交互,后端负责处理业务逻辑和数据存储,这一点大家应该都比较熟悉。

    五、Restful API在前端模型层的优势

    5.1 专注业务层逻辑

    使用Restful API设计前端模型层,开发者不用操心接口调用的那些细节,像发起HTTP请求、处理错误这些,都交给Model层或者统一的API管理模块去处理,自己只需要专注于具体的业务逻辑就行。

    5.2 数据状态管理

    Model层会负责管理接口返回的数据状态,还能把数据缓存起来。这样如果需要再次使用这些数据,就不用重复请求服务器了,性能也就提高了。开发者也能很方便地获取这些数据,进行后续的校验或者判断。

    5.3 统一的错误处理

    可以把网络错误(比如404、500这些状态码对应的错误)、权限错误(像401、403这些)以及业务错误都集中起来处理。开发者只需要关注和业务相关的错误,其他错误交给统一的处理机制就行。

    5.4 解耦接口层与业务层

    通过抽象出接口层(也就是API模块或者Model层),可以把HTTP请求的逻辑和具体的业务逻辑隔离开。业务层直接调用Model提供的接口,不用关心底层网络请求是怎么实现的,这样代码的结构更清晰,维护起来也更方便。

    以上就是我对Restful API前端接口模型架构的一些理解和分析,希望对大家有所帮助。如果在实际开发中遇到相关问题,欢迎一起讨论!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6819.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号