Nginx + Gunicorn + Flask 集成配置

想要配置好 Apache + mod_wsgi + Flask 问题真是太多了,随便换一个 Linux 发行版,或者不同的 Python 版本就得让 Google 排很多温室气体。Nginx 可以使用 uWSGI 和  Flask 串联起来,配置起来第一直觉好像也不容易,所以打算换一种方式,直接用一个 Python 的 WSGI HTTP Server, 必要的话再往前面加一个反向代理的 Nginx。这里就来试下 Nginx + Gunicorn + Flask  的完整配置。

在 Flask 的官方网站 Deployment Options 提到了各种生产环境下的部署办法,与 Gunicorn 类似的工具还有 uWSGI, Gevent, Twited Web, Hypercorn, Uvicorn, Daphne(来自于 django) 阅读全文 >>

关于 Apache 与 Flask 的集成经历

在 Flask 的官方文档 mod_wsgi(Apache), 说来倒是轻巧,实际操作起来不得不时刻要凝视眼前的无数大坑,或许 Linux, Apache 都用上比较新的版本会好一些。而我所用的环境是 AWS 上的 EC2, AMI 镜像发行版用 cat /proc/version 看到的是 Red Hat 7.2.1-2,内核为 4.14。照着 Flask  的官方文档是没做成功的,yum install mod_wsgi 只能安装到 Python2 的模块,pip install mod_wsgi 也不成功,所以只能使用 mod_wsgi 的源码来编译安装。

要能顺利编译过 mod_wsgi, 需要安装 Apache 2.2 和 Python 3.6 的 dev 版本。它的仓库里 Python3 最高版本只有 Python 3.6,要 Python 3.7, 3.8 可从源码编译安装。 

$ yum install gcc
$ yum install httpd-devel
$ yum install python36-devel

Red Hat 7.2 下的 Apache 真心的难用,不叫 Apache2 也不叫 httpd2,不像 Debian 系统下的 Apache2 做了模块化,基本上 Red Hat 7.2 的 httpd 的配置全在一个文件中 /etc/httpd/conf/httpd.conf。 阅读全文 >>

Flask 的替代品 aiohttp 和 Quart

本来只是为了研究一下 Flask  怎么去支持早已在 Python 的支持的 coroutine 功能,没想步子越迈越大,直顶到 aiohttp Web 服务器和 Flask  的异步实现版本 Quart。Flask 得费了好一番功夫去获得 EventLoop,可知 aiohttp 和 Quart 的路由方法直接就允许 async 的,那个 EventLoop 自然就在其中。从 async 的路由方法出发去调用别的异步方法就是一件十分轻松的事情。

下面来稍稍体验一下用分别用  aiohttp 和 Quart 实现简单的异步服务器,我们的关注点在它的异步路由。

阅读全文 >>

探索 Flask 对 asyncio 的支持

源于自己折腾的一个小 Flask 项目中,后台需访问多个 HTTP 服务,目前采用 ThreadPoolExecutor 多线程的方式处理的。但因访问 HTTP 服务有前后关联关系,如得到请求 A 的结果后再访问 B,这似乎用 Promise.then().then() 编程方式更合适些。于是巡着这一路子,翻出 Python 的各种相关部件来,比如 Python 对 coroutine(协程) 的支持,asyncio, 及后面的 async/await 关键子,aiohttp 组件,requests 的 async 替代品有 aiohttp, grequests, 和 httpx,aiohttp  可替代 Flask, 最后竟然找到了一个更彻底的 Flask 的 Async 版本 Quart。 

Python 3.4 引入了 asyncio 模块,基于生成器(yield 和 yield from) 和 @asyncio.coroutine 的方式来支持 coroutine(协程), 到 Python 3.5 后有了 async/await(@asyncio.corouting 替换为 async, yield from 替换为 await) 关键字,协程的实现变得更为简单。Python 3.4  使用 coroutine 的方式我们跳过,直接看

阅读全文 >>

Python datetime 处理时区信息

Python 常用日期处理 -- 内置模块 datetime 探讨了 Python  如何使用 datetime, 如果是一个跨时区的应用(Web 应用都是),就不能只存储一个时间而不带时区,如此,全球用户将会看到一个相同的时间字符串,白天黑夜就错乱了。比说用户信息的更新时间存储为 2020-07-07 13:46:08, 上海的用户和芝加哥的用户看到的是同一个时间字符串,实质上却相差好多个小时。

我们可以这么做,在服务端只存储一个 Timestamp 长整型值或 UTC 时间,Timestamp 是无关乎时区的,它总是相对于一个 UTC 时间的偏移值; 然后由客户端根据本地时区来显示当地时间。不过在服务端存储为 Timestamp 或 UTC 可读性就不强了,打开文件看到 Timestamp 整形值,大脑是无法直接转换为日期,UTC 时间略好一些。

另一种做法可在服务端存储为开发者便于理解的带时区的时间,如 2020-07-07T13:46:08.342+08:00, 客户获得该时间,因为带有时区信息也就能转换为客户端本地时间。

客户端请求时还可以把本地的时区信息传送给服务端,由服务端转换为相应的本地时间发送给客户端,但 HTTP 头信息默认不带时区信息,客户端必须主动发送它。 阅读全文 >>

Flask, Vue.js 中集成 Bootstrap/BootstrapVue

紧接上一篇 Flask 和 Vue.js 开发及整合部署实例,来体验一下它们与 Bootstrap/BootstrapVue 的集成。漂亮的网站少不得一个好的 CSS 框架,现在有许许多的 CSS 框架可选,纯 CSS 的, 轻量级的, 含 JS 的 CSS 框架,如 Pure, Bulma, Spectre, 国产的 Element 等。而我总觉得 Bootstrap 更是五臟俱全,像 Element 专为 Vue.js 打造的一样,Bootstrap 也有 BootstrpVue 那样一个结晶品。

本文准确的内容应该是关于 Vue.js 与 Bootstrap/BootstrapVue 的话题,与 Flask 没什么事,不过这里呢,还是强拉上 Flask, 由 Flask 的 API 来产生一些数据。

同样是阅读 Flask和Vue.js构建全栈单页面web应用【通过Flask开发RESTful API】的一个实践品。本篇基于 Flask 和 Vue.js 开发及整合部署实例 中的步骤建立的项目 flask-vue-app,方便起见,用了一个新项目名称 flask-vue-bootstrap。记得我们为 Flask 和 Vue.js 分别建立了 backend  和 frontend 两个子项目。 阅读全文 >>

Flask 和 Vue.js 开发及整合部署实例

想做些简单的 Web 工具,首先想到的是 Flask + Vue.js, 当然可以完全用 Flask 自己的页面模板 Jinja2, 但一个网站项目不能享受到像 Vue.js, React 类似框架的灵活性真是太可惜了。于是 Flask 只专注于 API, 页面逻辑全用 Vue.js 的组合就成了我的首选,Flask 方面还能进一步选择 FlaskRESTful 框架。还需做得更漂亮的话,CSS 框架可选择 Bootstrap 或与 Vue 紧密集成的 BootstrapVue, 这是后话。

本文主要参考 Flask和Vue.js构建全栈单页面web应用【通过Flask开发RESTful API】的前部分,英文原文在这里 Developing a Single Page App with Flask and Vue.js

开发过程中我们可以保持 Flask 和  Vue.js 为单独的两个项目,并启动各自的服务,比如 Flask 是 http://localhost:5000, Vue.js 项目通过 npm run serve 启动在 http://localhost:8080,借助于 node js 的功能,修改 Vue.js 项目的内容能够自动刷新网页。要是开发中把静态文件全放在  Flask 项目中,那么任何对静态文件的修改都必须重启 Flask  服务。虽然 Debug 模式启动的 Flask 在看到它的目录中有任何修改时也能自动重启,但对静态文件的修改重启 Flask 没这个必要性。 

但部署时需进一步整合,最终只需要启动 Flask  服务,而无须两个,方便部署。如果是以 Docker 容器的方式发布,使用 docker-compose 来编排两个容器来发布也还算不错。更专业的部署方式应该是 Vue.js 的静态内容放到专门的 Web 服务器,如  Apache/Nginx 中,Flask 也通过 wsgi 与 Web 服务器集成起来。 阅读全文 >>

Docker attach 后断开时不退出容器

docker attach 可以连接上 Docker 容器的标准输入,输出和错误输出。比如 docker attach 连接后就能显示容器中用 ENTRYPOINT/CMD 启动进程的输出内容内容。想要断开会话连接怎么做呢?ctrl - c, 控制台是不再显示了,可以容器也被终止了,显然这是一个危险的操作。

ctrl - c 不仅仅关闭了 docker attach 本身,因为它的默认参数 --sig-proxytrue,所以 SIGKILL 信号同时传递到了 ENTRYPOINT/CMD 的 PID 1 的进程,所以形成了双杀的效果。我们来试一下

如果是在生产环境下,用 docker attach 连接下控制台看下输出,然后不小心像终止 tail -f 命令一样用 ctrl - c  退出,结果服务断了。所以更为小心的操作还是用 docker logsdocker attach 的优势只是在于能查看实时的控制台输出。 阅读全文 >>

Mockito 的 anyString(), any(Foo.class) 等不能匹配 null 值

使用 Mockito Mock 方法式,一直以为可以用 anyString(), any(Foo.class) 等匹配 null 值,其实不行,null 值必须显式的用 null, 或 eq(null) 来匹配。anyString(), anyInt() 等只能匹配非 null 值,查看它们的返回值实际是 "" 和 0 等, 而更为特别的是 any(Foo.class) 看到的是 null, 仍然不能匹配 null 值。进一步用 Mockito.mockingDetails(mock).printInvocations() 打印出的内容,anyString(), any(Foo.class) 都会显示为 null 值。

说的有点罗嗦,看下面的例子, 被测试类 UserDao,sql 和 sqlArguments 由各自的 setter 方法来控制,默认它们都为 null 阅读全文 >>

Python 列表的排序 - sort/sorted

Python 集合的遍历,推导及 filter/map/reduce 操作 中讲了对集合的 filter, map 和 reduce 操作,那还有 sort 排序呢?像 Java 一样,Python  也提供了 sort() 和 sorted() 方法。

sort() 是 list 的实例方法, sorted() 是一个内置函数。Python 中也是只有 list 才有顺序。

list.sort() 方法

查看 Python 3 中的 list.sort() 方法(help(list.sort))

Help on method_descriptor:

sort(self, /, *, key=None, reverse=False)
Stable sort *IN PLACE*.

Python 的 list.sort() 方法和 Java List.sort() 方法一样的,都是 IN PLACE 排序,没有返回值。实际看下各种排序场景 阅读全文 >>