构建个人博客网站(基于Python Flask)

 

本文由 Ficow Shen 首发于 Ficow Shen's Blog.

 

文章概览

  • 前言
  • Sketch
  • HTML, CSS, JavaScript
  • Python & Flask & MySQL & SQLAlchemy
  • Gunicorn & Terminal & Command
  • Domain name
  • Nginx & Certbot

 
 

前言

你是否曾经尝试过搭建个人博客网站?
Hugo, HexoWordPress 这些耳熟能详的产品,你是否也曾经试用过?
这些产品可以让你极速搭建个人博客网站,而且你不需要了解太多技术细节。

 

如果你只是想有一个简单的博客网站只是希望能够进行内容创作、发表,那么我建议你使用那些产品停止阅读这篇文章

如果你想DIY你的博客想更深入地了解一个博客系统想学习一些Web和后端技术,那么我建议你继续阅读,然后 自己搭建一个博客网站

 

为何选择 PythonFlask 进行后端开发?

  • Python 简单易学
  • 对脚本语言感兴趣,通过学习 Python 来熟悉 脚本语言
  • Flask 是一个知名且被广泛应用的后端开发框架,社区非常活跃
  • Python 和 Flask 都有丰富的第三方库

当然,除了 Python,你也可以选择 PHP, Golang 等作为后端开发语言。

在学习开始之前,我向你推荐一个网站:Learn X in Y minutes
正如网站名称说的那样,你可以在Y分钟内学习X。该站可以加快你的学习进程,让你尽快看到内容的全貌。

 
 

Sketch

Sketch

使用 Sketch,主要是为了设计博客页面
当然,也可以用 PhotoShop 这种类似的软件。
然后,你就可以参考别人的个人博客页面,然后设计自己的博客页面的版式、配色等等。

也许有人会问,有很多现成的主题可以用,为什么还要自己设计呢?

如果你想学习和应用 Web技术,尤其是 CSS 中的 Selector、Flexbox,那么自己写就可以让你的学习效果更好。
如果你不感兴趣,可以跳过这一步,直接去用别人造好的轮子即可。

如果你觉得 Sketch 实在太贵,请看这里
Sketch 是个很优秀的产品,请您支持正版~

 
 

HTML, CSS, JavaScript

 

HTML 示例:

 <!DOCTYPE html>
<html>
	<head>
		<title>Page Title</title>
	</head>
	<body>
		<h1>This is a Heading</h1>
		<p>This is a paragraph.</p>
	</body>
</html> 

CSS 示例:

body {
  background-color: lightblue;
}
h1 {
  color: white;
  text-align: center;
}
p {
  font-family: verdana;
  font-size: 20px;
}

JavaScript 示例:

document.getElementById("demo").innerHTML = "Hello JavaScript"; 

 

在开始学习之前,我在知乎了解了 零基础如何迅速学习前端?
然后,在 菜鸟教程 看完了 HTML, CSS, JavaScript 的基础内容。

相关的基础知识必须过一遍,甚至几遍!
要确保自己知道这些技术包含哪些内容,然后你后面需要用到的时候,就可以很容易地找到它们并把它们用起来。

除此之外,还在 MDN 单独学习了一些技术点,比如:Flexbox.
以及 阮一峰的网络日志

看了这些东西之后,就需要实操练习。你可以去找一些博客网站来模仿,通过模仿别人的网站来熟悉前端的布局技术。
其实,要点就是:看基础知识,然后模仿着写,巩固学习效果

掌握了这些知识,你就可以写出静态的网页了。

 
 

Python & Flask & MySQL & SQLAlchemy

 

Python 示例:

# -*- coding: UTF-8 -*-

# 该实例输出 Hello World!
print('Hello World!')

 

让静态网页“活”起来的关键是后端提供的数据支持。
学习 Python & Flask & MySQL 之后,你就可以自己定义后端接口,然后为前端提供数据支持。

学习 Python3,了解 Python 的基础知识点。

掌握了 Python 基础知识之后,就可以开始学习 Flask 了。
点开 Documentation,里面会有 Quickstart,也有 Tutorial。这两个部分,不容错过!

如果觉得阅读英文文档的难度太高,你可以看 Flask Web开发:基于Python的Web应用开发实战
这本书的资源仅供参考,请您支持正版~

 

另外,Flask Tutorial 中使用的是SQLite,但是我建议你使用更好的关系型数据库,比如:MySQL 或者 PostgreSQL
如何安装和使用这些数据库,你可以参考官方文档或者去搜索引擎找相关的文章来学习。

 

学完这些内容之后,你基本上就已经学会了:
定义后端接口执行数据库CRUD操作返回网页数据给前端单元测试 以及 基本的网络安全知识

把前端和后端的内容结合在一起,网页的内容就任由你来定义。

 

如果你觉得书写 SQL 语句很烦人,那么我推荐你使用知名的ORM【对象关系映射(Object Relational Mapping)】 框架 SQLAlchemy
你可以去官方网站找 Tutorial 来快速入门, 比如:SQLAlchemy tutorial

 

这里有两个示例可供参考。

使用 SQL 语句的示例:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sqlalchemy import create_engine
from sqlalchemy.sql import text

eng = create_engine("mysql://testuser:test623@localhost/testdb")

with eng.connect() as con:

    con.execute(text('DROP TABLE IF EXISTS Cars'))
    con.execute(text('''CREATE TABLE Cars(Id INTEGER PRIMARY KEY, 
                 Name TEXT, Price INTEGER)'''))

    data = ( { "Id": 1, "Name": "Audi", "Price": 52642 },
             { "Id": 2, "Name": "Mercedes", "Price": 57127 },
             { "Id": 3, "Name": "Skoda", "Price": 9000 },
             { "Id": 4, "Name": "Volvo", "Price": 29000 },
             { "Id": 5, "Name": "Bentley", "Price": 350000 },
             { "Id": 6, "Name": "Citroen", "Price": 21000 },
             { "Id": 7, "Name": "Hummer", "Price": 41400 },
             { "Id": 8, "Name": "Volkswagen", "Price": 21600 }
    )
    
    for line in data:
        con.execute(text("""INSERT INTO Cars(Id, Name, Price) 
            VALUES(:Id, :Name, :Price)"""), **line)

 

使用 SQLAlchemy ORM 的示例:

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker

eng = create_engine('sqlite:///:memory:')

Base = declarative_base()
 
class Car(Base):
    __tablename__ = "Cars"
 
    Id = Column(Integer, primary_key=True)
    Name = Column(String)  
    Price = Column(Integer)
        
Base.metadata.bind = eng        
Base.metadata.create_all()        
        
Session = sessionmaker(bind=eng)
ses = Session()    

ses.add_all(
   [Car(Id=1, Name='Audi', Price=52642), 
    Car(Id=2, Name='Mercedes', Price=57127),
    Car(Id=3, Name='Skoda', Price=9000),
    Car(Id=4, Name='Volvo', Price=29000),
    Car(Id=5, Name='Bentley', Price=350000),
    Car(Id=6, Name='Citroen', Price=21000),
    Car(Id=7, Name='Hummer', Price=41400),
    Car(Id=8, Name='Volkswagen', Price=21600)])
ses.commit()

观察后可以发现,使用了 ORM 可以帮助我们专注于业务逻辑。
不用担心 SQL 语句是否打错字,也不用担心它是否能正常执行并返回预期的结果。

 
 

Gunicorn & Terminal & Command

学习完 Flask 之后,你已经知道了开发服务器和生产服务器的区别。
为了更好的性能以及安全性,在部署博客系统的时候,你需要使用一个生产服务器。

我选择了 Gunicorn,配置比较简单(入门容易),而且用户群也比较庞大(遇到问题更容易解决)。
参考 Gunicorn 的教程,你可以很容易地完成相关的配置。

 

Gunicorn 配置示例:

import multiprocessing

bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1

backlog = 2048
worker_class = "gevent"
worker_connections = 1000
daemon = False
debug = True
proc_name = 'gunicorn_demo'
pidfile = './log/gunicorn.pid'
errorlog = './log/gunicorn.log'

 
使用 Gunicorn 之后,你可以很容易地配置后端应用的访问地址、进程数、日志路径、运行模式等等。

 

在你打算部署服务器时,你会发现你必须使用 命令行工具

首先,启动 Gunicorn 需要执行命令行指令,比如:gunicorn --paste development.ini -b :8080 --chdir /path/to/project
然后,连接远程服务器需要使用 SSH, 比如: ssh root@127.0.0.1

推荐你学习 Linux 教程Shell 教程 。在部署后台系统到远程服务器的过程中,你会反复用到如 cd, ls, vim 等这些命令。所以,学习这些命令是必需的步骤。

 

如果你还没有购买云服务器,那我推荐你使用 Vultr 的服务器。
优点:便宜、不用备案、轻松部署强力爱国上网等等
缺点:延迟高、经常有黑客来访等等

当然,你也可以购买知名的 AWS、阿里云、腾讯云、UCloud 等等厂商的云服务器。

 
 

Domain name

拥有自己的博客的同时,你是不是也希望能够拥有一个特别的网站域名,比如自己的名字?

现在以 http://ficow.cn 为例来讲解域名相关的知识。

你可以访问 http://www.ficow.cn,也可以访问 http://ficow.cn
但是,如果我访问 http://123.ficow.cn 就无法看到正常的页面。为什么呢?
因为我在域名解析页面进行了相应的配置,http://ficow.cnhttp://www.ficow.cn 都是我希望别人可以正常访问的网页。

 

阿里云 域名注册首页

我是在 阿里云(原万网) 购买了 ficow.cn 这个域名,当然你也可以选择其他的域名提供商购买域名。

 

在购买了域名之后,就可以登录控制台进行域名解析

控制台 域名解析

在主机记录这一列,我配置了 wwwblog。这两个均指向了同一个IP,也就意味着目前我是依靠这一台服务器来处理个人首页博客
关于域名配置的详细内容,你可以参考域名提供商提供的帮助文档,也可以直接通过搜索引擎寻找答案,这里就不赘述了。

但是,你是不是比较好奇,两个不同的主机记录竟然指向了同一台服务器。服务器是如何对不同的主机记录进行解析的呢? 接下来,Nginx 会告诉你答案~

 
 

Nginx & Certbot

Nginx 是一个高性能反向代理服务器,它可以将远程服务器上收到的数据转发给你的后台程序。用它来处理静态文件请求非常方便。

这是一个 Nginx server 的配置 Demo:

server
{
        access_log /home/xxx/path/to/project custom_log;
        server_name blog.ficow.cn;

        charset utf-8;
        root /home/xxx/path/to/project;

        # Proxy connections to the application servers
        location / {
            proxy_pass         http://0.0.0.0:5000;
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Forwarded-Proto $scheme;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
            client_max_body_size 10M;
        }
}

你可以通过简单地配置 Nginx 来监听 80 端口,然后让它根据域名来区分以及转发数据给你的后台程序。
在上面的示例中,Nginx 会把指向 blog.ficow.cn 的访问请求转发给 http://0.0.0.0:5000, 限制客户端请求中body最大为 10M。

当然,你可以让多个 server_name 都使用这同一套配置。你还可以定义多个 server,然后对不同的 server_name 进行不同的定制化处理,比如:负载均衡

想了解更多关于如何配置 Nginx 的内容,请参考官网文档。

如果你希望你的博客网站支持 HTTPS,我推荐你使用 Certbot
Certbot 的最大优势就是:免费、易用,这对于一个个人博客系统来说,简直完美~

 

在 Ubuntu 系统上安装 Certbot 的示例:

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx 

自动配置 Nginx 的 SSL 相关参数:

certbot --nginx

编辑定时任务,定期调起 Certbot 去更新 SSL 证书:

crontab -e

插入本行内容,并保存退出,定时任务即可生效

# 分  时  某月中的几号  几月  星期几  *代表任何时候 ,分隔多个相同类型的参数
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew

如果系统默认打开的编辑器不是vim,可以修改环境变量
在~/.profile中加入以下内容,并保存退出

vim ~/.profile
export EDITOR="/usr/bin/vim";

加载更新的EDITOR配置:

source ~/.profile

然后再重新使用crontab -e添加定时更新 SSL 证书的任务即可。

然后,尝试使用HTTPS来访问你的博客吧!

posted @ 2020-04-11 13:46  Ficow  阅读(1141)  评论(0编辑  收藏