实例讲解基于 Flask+React 的全栈开发和部署

我有时在 Web 上浏览信息时,会浏览 Github Trending, Hacker News稀土掘金 等技术社区的资讯或文章,但觉得逐个去看很费时又不灵活。后来我发现国外有一款叫 Panda 的产品,它聚合了互联网大多数领域的信息,使用起来确实很不错,唯一的遗憾就是没有互联网中文领域的信息,于是我就萌生了一个想法:写个爬虫,把经常看的网站的资讯爬下来,并显示出来。

有了想法,接下来就是要怎么实现的问题了。虽然有不少解决方法,但后来为了尝试使用 React,就采用了 Flask + React + Redux 的技术栈。其中:

  • Flask 用于在后台提供 api 服务
  • React 用于构建 UI
  • Redux 用于数据流管理

目前项目已经实现了基本功能,项目源码:Github 地址。目前界面大概如下:

home

 

前端开发

前端的开发主要涉及两大部分:ReactRedux,React 作为「显示层」(View layer) 用,Redux 作为「数据层」(Model layer) 用。

我们先总体了解一下 React+Redux 的基本工作流程,一图胜千言(该说的基本都在图里面了):

我们可以看到,整个数据流是单向循环的

其中:

  • React 提供应用的 View 层,表现为组件,分为容器组件(container)和普通显示组件(component);
  • Redux 包含三个部分:Action,Reducer 和 Store:
    • Action 本质上是一个 JS 对象,它至少需要一个元素:type,用于标识 action;
    • Middleware(中间件)用于在 Action 发起之后,到达 Reducer 之前做一些操作,比如异步 Action,Api 请求等;
    • Reducer 是一个函数:(previousState, action) => newState,可理解为动作的处理中心,处理各种动作并生成新的 state,返回给 Store;
    • Store 是整个应用的状态管理中心,容器组件可以从 Store 中获取所需要的状态;

项目前端的源码在 client 目录中,下面是一些主要的目录:

React 开发

React 部分的开发主要涉及 container 和 component:

  • container 负责接收 store 中的 state 和发送 action,一般和 store 直接连接;
  • component 位于 container 的内部,它们一般不和 store 直接连接,而是从父组件 container 获取数据作为 props,所有操作也是通过回调完成,component 一般会多次使用;

在本项目中,container 对应的原型如下:

container

而 component 则主要有两个:一个是选择组件,一个是信息显示组件,如下:

选择组件 信息显示组件

这些 component 会被多次使用。

下面,我们主要看一下容器组件 (对应 App.js) 的代码(只显示部分重要的代码):

其中,

  • constructor(props) 是一个构造函数,在创建组件的时候会被调用一次;
  • componentDidMount() 这个方法在组件加载完毕之后会被调用一次;
  • componentWillReceiveProps() 这个方法在组件接收到一个新的 prop 时会被执行;

上面这几个函数是组件生命周期(react component lifecycle)函数,更多的组件生命周期函数可在此查看。

  • react-redux 这个库的作用从名字就可看出,它用于连接 react 和 redux,也就是连接容器组件和 store;
  • mapStateToProps 这个函数用于建立一个从(外部的)state 对象到 UI 组件的 props 对象的映射关系,它会订阅 Store 中的 state,每当有 state 更新时,它就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染;

Redux 开发

上文说过,Redux 部分的开发主要包含:action,reducer 和 store,其中,store 是应用的状态管理中心,当收到新的 state 时,会触发组件重新渲染,reducer 是应用的动作处理中心,负责处理动作并产生新的状态,将其返回给 store。

在本项目中,有两个 action,一个是站点选择(如 Github,Hacker News),另一个是信息获取,action 的部分代码如下:

可以看到,action 就是一个普通的 JS 对象,它有一个属性 type 是必须的,用来标识 action。

reducer 是一个含有 switch 的函数,接收当前 state 和 action 作为参数,返回一个新的 state,比如:

再来看一下 store:

其中,applyMiddleware() 用于告诉 redux 需要用到那些中间件,比如异步操作需要用到 thunk 中间件,还有 api 请求需要用到我们自己写的中间件。

后端开发

后端的开发主要是爬虫,目前的爬虫比较简单,基本上是静态页面的爬虫,主要就是 HTML 解析和提取。如果要爬取稀土掘金知乎专栏等网站,可能会涉及到登录验证抵御反爬虫等机制,后续也将进一步开发。

后端的代码在 server 目录:

后端通过 Flask 以 api 的形式给前端提供数据,下面是部分代码:

部署

本项目的部署采用 nginx+gunicorn+supervisor 的方式,其中:

  • nginx 用来做反向代理服务器:通过接收 Internet 上的连接请求,将请求转发给内网中的目标服务器,再将从目标服务器得到的结果返回给 Internet 上请求连接的客户端(比如浏览器);
  • gunicorn 是一个高效的 Python WSGI Server,我们通常用它来运行 WSGI (Web Server Gateway Interface,Web 服务器网关接口) 应用(比如本项目的 Flask 应用);
  • supervisor 是一个进程管理工具,可以很方便地启动、关闭和重启进程等;

项目部署需要用到的文件在 deploy 目录下:

本项目采用了 Fabric 自动部署神器,它允许我们不用直接登录服务器就可以在本地执行远程操作,比如安装软件,删除文件等。

fabfile.py 文件的部分代码如下:

其中,env.hosts 指定了远程服务器,env.key_filename 指定了私钥的路径,这样我们就可以免密码登录服务器了。根据实际情况修改上面的相关参数,比如服务器地址,用户名,服务器端口和项目路径等,就可以使用了。注意,在部署之前,我们应该先对前端的资源进行加载和构建,在 deploy 目录使用如下命令:

当然,你也可以直接到 client 目录下,运行命令:

如果构建没有出现错误,就可以进行部署了,在 deploy 目录使用如下命令进行部署:

总结

  • 本项目前端使用 React+Redux,后端使用 Flask,这也算是一种比较典型的开发方式了,当然,你也可以使用 Node.js 来做后端。
  • 前端的开发需要知道数据的流向:

flow

  • 后端的开发主要是爬虫,Flask 在本项目只是作为一个后台框架,对外提供 api 服务;

参考资料

1 11 收藏 1 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部