用Tornado来实现你的服务器梦想,Python编程纯干货教学

  • A+
所属分类:技术教程

看完此文章,你将可以独立完成:

1. 在服务器上可以写一个简单的静态网页,并访问

2. 可以为你的App写接口,提供Json格式的数据

我相信,博客里面大神很多,而且应该有很多是干IT的,而且也有些是学生,这些人可能会对编程感兴趣。所以,我就在这里班门弄斧,给大家讲一下,如何用Tornado来搭建你自己的初级服务器。

授人以鱼不如授人以渔,这就是我为什么要写这些文章的缘由。今天既然能够通过爬取的数据来访问到小草,那么明天我就可以通过服务器上访问每天新闻的最新消息,或者我关注的人的微博更新,或者美剧是否又跟新了,或者视频网站是否又出新视频了,或者一些论坛是否发了最新的帖子,甚至每天早晨一起来,都可以通过自己的算法再结合昨天的股票数据,来推测今天大盘的涨跌,这些东西背后的原理其实都差不多的。所以,不要把自己的思路局限在一点,要扩散,要放开,这样才会有骚操作的出现。

行了,废话不闲扯了,来开始说说我们今天的主角:Tornado吧。

啥是Tornado

Tornado就是龙卷风,哦不,这里说的Tornado是一种 Web 服务器软件的开源版本。Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。

Tornado需要用Python编写,所以,这一系列下来,我们都是用的Python来搞事情,就和我之前说的,Python这个语言,最适合搞事情了!

这里要说一点,Web框架有很多种,不同语言有不同的框架,而且特点都不一样,就Ptyhon而言,用Python开发的Web框架也有好几种,Django,Flask,Tornado,这些框架,也是各有各的特点。所以,我想说的是,至于要用那种框架,请结合你自身的需求来选择。不要盲目的抓起一个随便用,这样将来会坑了自己。我们这里,就是小型服务,自娱自乐用,所以,没有那么多顾虑,随便抓起来一个用就OK,这不,我抓的就Tornado。

把Tornado搞到服务器上

首先,服务器或者你本地的机器上面,应该是有Python的,推荐Python3,然后,你的机器应该是有pip的。

我们需要通过pip来安装Tornado

  1. # pip install tornado

安装完成,如果想测试是否安装功,只需要进入Python,然后输入import tornado,如果没有报错,就说明安装成功。

接着,我们来搞一下本地的配置。

本地,我推荐使用PyCharm来做IDE。这个IDE功能还算可以,如果你已经有自己习惯的IDE,可以略过此处。

PyCharm官网上有两个可下载的版本:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

推荐下载第一个,Professional,这个版本功能很强大,而且支持很多Web框架的插件。

但是好多人会发现,这个是收费版本的啊,那怎么用?

别急,破解方法非常简单,第一次打开PyCharm的时候,选择License server激活,然后填入:http://im.js.cn:8888 或 http://idea.java.sx/ 或http://xidea.online,然后点Activate激活即可。

接着,我们需要将本地的代码和服务端的代码要同步起来,做好映射,设置的步骤也很简单。这里,我们假设远端的服务器地址是39.11.12.123。

在Tools -> Deployment -> Configuration里面:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

 

点击左上角的 + 号:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

 

出来的对话框里,名字随便写,但是下面的要选择SFTP。

用Tornado来实现你的服务器梦想,Python编程纯干货教学

接着,下面这张图,第一个红框里面填写远程服务器的ip地址:39.11.12.123,第二个填写你服务器上的登录账户名称,一般是root,第三个就是密码。

用Tornado来实现你的服务器梦想,Python编程纯干货教学

接着第二页,Mapping里面,第二个红框里面,填写你本机的工程目录地址,第三个红框填写在服务器上的工程目录地址(提前建好)。

用Tornado来实现你的服务器梦想,Python编程纯干货教学

然后点击OK。接着,在Tools -> Deployment -> Automatic Upload点击打钩,这样每次编写完一个文件,代码就可以自动同步到服务器上了。

用Tornado来实现你的服务器梦想,Python编程纯干货教学

每次如果需要同步的话,可以在Tools -> Deployment菜单里面,选择Upload to XXXX就行,或者在需要上传的文件图标点击右键,在Deployment里面选择就可以。很方便。上传成功的样子大概就是这样:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

好了,我们接下来就要尝试着编写我们的代码了。但是,对于第一次接触新框架的你,我们还是先看一下Tornad的“Hello World”怎么写吧。

  1. import tornado.ioloop
  2. import tornado.web
  3. class MainHandler(tornado.web.RequestHandler):
  4.     def get(self):    # 3
  5.         self.write(\"Hello, world\")    # 4
  6. def make_app():
  7.     return tornado.web.Application([
  8.         (r\"/\", MainHandler),    # 2
  9.     ])
  10. if __name__ == \"__main__\":
  11.     app = make_app()    # 1
  12.     app.listen(8888)
  13.     tornado.ioloop.IOLoop.current().start()

在这个里面,最关键的,有这么几个地方:

1. make_app()声明一个tornado的application,里面就规定了服务器接收处理的url路径。

2.服务器接收了url,将会把请求交给MainHandler()来做处理。

3.MainHandler中的get方法,是用来处理HTTP GET请求的。

4.返回结果,只返回了一个字符串。

OK,上面简单的分析,就是Tornado处理一个网络请求的逻辑。捋顺这个逻辑之后,我们接下来就开始简单的编写一下我们自己的服务端代码吧。

撸码时刻

明确一下我们的两个目的:

1.我们的网站能够访问数据库并且显示在网页上

2.我们的网站能够做到给App提供数据接口功能,返回Json格式的数据。

好的,下面我们就起来撸代码,不对,是撸起来代码。

遵循我们上面所说的,定义url路径,然后写Handler。所以,我就先按照这个思路,把工程目录按照这个样子建立了一下:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

然后,我们在main.py这个文件里面编写代码如下:

  1. class Application(tornado.web.Application):
  2.     def __init__(self):
  3.         handlers = [
  4.             (r\"/web/\", WebHandle),
  5.             (r\"/json/\", JsonHandle),
  6.         ]
  7.         # 定义tornado服务器的配置项,如static/templates目录位置,debug级别等
  8.         settings = dict(
  9.             debug=True,
  10.             static_path=os.path.join(os.path.dirname(__file__), \"static\"),
  11.             template_path=os.path.join(os.path.dirname(__file__), \"templates\")
  12.         )
  13.         tornado.web.Application.__init__(self, handlers, **settings)
  14. if __name__ == \"__main__\":
  15.     print(\"Tornado server is ready for service\r\")
  16.     Application().listen(8000, xheaders=True)
  17.     tornado.ioloop.IOLoop.current().start()

这里简单做一下解释:

我们定义两个Handler,一个是返回网页版本的Handler,另一个是返回Json版本的;我们的Application的写法也和Hellow world例子中写的不一样,我们这样写,可以自定义很多设置,比如路径,是否Debug模式之类的。

那么我们接下来看看连个Handler怎么写的:

  1. # views.json
  2. class JsonHandle(tornado.web.RequestHandler):
  3.     def get(self, *args, **kwargs):
  4.         self.write(\"json view\")
  5. # views.web
  6. class WebHandle(tornado.web.RequestHandler):
  7.     def get(self, *args, **kwargs):
  8.         self.write(\"web view\")

这里是两个及其简单的实现,我们来看一下效果:

用Tornado来实现你的服务器梦想,Python编程纯干货教学
用Tornado来实现你的服务器梦想,Python编程纯干货教学

下面这个是访问错误的url出现的页面,因为我们开了Debug模式,所以页面长这个样子:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

404页面的问题我们之后会说到。

到这里位置,我们有一个地方不知道大家发现没有,十分的不灵活,就是上面url匹配的地方。这里指定了:http://xxxxxx/json/只能用JsonHandler来处理,但是如果来了http://xxxxxx/json/XX,他就会报错,页面未找到。处理这样的请求,让我们的服务变得更加强大,更加健壮,我们决定,新加一个url_router,在一定程度上,用它来控制我们的url匹配。

  1. \"\"\"
  2.     url_router.py
  3. \"\"\"
  4. def include(module):
  5.     res = import_module(module)
  6.     urls = getattr(res, 'urls', res)
  7.     return urls
  8. def url_wrapper(urls):
  9.     wrapper_list = []
  10.     for url in urls:
  11.         path, handles = url
  12.         if isinstance(handles, (tuple, list)):
  13.             for handle in handles:
  14.                 pattern, handle_class = handle
  15.                 wrap = ('{0}{1}'.format(path, pattern), handle_class)
  16.                 wrapper_list.append(wrap)
  17.         else:
  18.             wrapper_list.append((path, handles))
  19.     return wrapper_list

有了router,我们的main文件和handler文件都应该修改一下,在views.json和views.web目录下,分别建立json_urls.py和web_urls.py:

  1. \"\"\"
  2.     main.py
  3. \"\"\"
  4. class Application(tornado.web.Application):
  5.     def __init__(self):
  6.         # >>>> 不一样的地方开始
  7.         handlers = url_wrapper([
  8.             (r\"/json/\", include('views.json.json_urls')),
  9.             (r\"/web/\", include('views.web.web_urls')),
  10.         ])
  11.         # 不一样的地方结束 <<<<
  12.         # 定义tornado服务器的配置项,如static/templates目录位置,debug级别等
  13. \"\"\"
  14.     json_urls.py
  15. \"\"\"        
  16. urls=[
  17.     (r'', JsonHandle)
  18. ]
  19. \"\"\"
  20.     web_urls.py
  21. \"\"\"
  22. urls = [
  23.     (r\"\", WebHandle)
  24. ]

这样写,虽然看上去比较乱一些,但是相当灵活。能够使我们的url变得丰富。比如,如果我想添加一个查看全部json文件的url,那么我只需要在json_urls里面,添加一个(r'/all', GetAllHandler)即可,然后在json_view.py里面实现GetAllHandler就可以了。这样做完,我们的服务器就可以同时处理http://xxxxxx/json/和http://xxxxxx/json/all两个url了,而且是不同的handler处理。

此时此刻,我们大概的框架基本搭建完成。下面就来主要实现一下handler里面的功能吧。

因为我们要实现的是从数据库里面读取了数据在显示到网页上,所以,这里我们用到了PyMongo这个库。这个库是Python专门用来操作MongoDB的,炒鸡简单好用。

我们先来完成Json部分。

我们要在JsonHandler中,实现get()方法。这里,我们首先从数据库中读取出来数据,然后,得将数据转换成dict()格式,因为PyMongo读取出来的数据,不能够直接转成Json,因为里面有个叫Object_id的东西,所以,这里我们就手动转一下。然后,把数据用self.write(json.dumps({"data": {"block": return_data, "curTime": cur_time}}))的形式返回回去就好。结构相当简单,大致代码如下:

  1. class JsonHandle(tornado.web.RequestHandler):
  2.     def get(self):
  3.         # 从数据库中读取数据
  4.         self.client = pymongo.MongoClient(\"mongodb://39.11.12.123/\", 27017)
  5.         self.db = self.client[\"DailyProject\"]
  6.         self.table = self.db[\"table\"]
  7.         result = self.table.find()
  8.         # 得到当前时间
  9.         time = datetime.datetime.now()
  10.         cur_time = str(time.year) + \"-\" + str(time.month) + \"-\" + str(time.day)
  11.         # 筛选出合适的数据
  12.         temp_posts = []
  13.         posts = []
  14.         for item in result:
  15.             temp_posts.append(item)
  16.             temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
  17.         for item in temp_posts:
  18.             if item['post_day_time'] == cur_time:
  19.                 posts.append(item)
  20.         # 将数据转换成dict()类型,方便转换成Json
  21.         return_data = []
  22.         for item in posts:
  23.             temp_dic = {'postId': item['post_id'], 'postTitle': item['post_title'],
  24.                         'postPartUrl': item['post_part_url']}
  25.             return_data.append(temp_dic)
  26.         # 返回Json格式的数据
  27.         self.write(json.dumps({\"data\": {\"block\": return_data, \"curTime\": cur_time})

下面是效果:
用Tornado来实现你的服务器梦想,Python编程纯干货教学

用Tornado来实现你的服务器梦想,Python编程纯干货教学

这样,实现起来是不是超级酷。这里是实现了get方法,你也可以实现post方法来处理HTTP POST请求。具体的逻辑还是要根据你具体的业务来编写。反正最后用json.dumps返回就可以了。

小技巧:如果你返回的json格式都差不多,可以抽离出来,写一个模板,以后返回结果直接将数据传给模板就好。不需要在每个方法都写一遍json的格式,那样如果修改起来,会很费事儿。

接下来实现web格式的返回。

Web返回结果,我们这里就用到了html的东西。首先,我们得在template里面建一个index.html文件。然后,在WebHandler中,最后返回结果写成:self.render("index.html", info=posts, today=cur_time)这样就可以了。这里简单说一下,第一个参数,是你template里面对应的html文件。第二个参数和第三个参数,是你需要传给前端的数据。名字随便叫,但是要和html里面保持一致。

Handler的代码大致如下:

  1. class WebHandle(tornado.web.RequestHandler):
  2.     def get(self):
  3.         self.client = pymongo.MongoClient(\"mongodb://39.11.12.123/\", 27017)
  4.         self.db = self.client[\"DailyProject\"]
  5.         self.table = self.db[\"table\"]
  6.         result = self.table.find()
  7.         time = datetime.datetime.now()
  8.         cur_time = str(time.year) + \"-\" + str(time.month) + \"-\" + str(time.day)
  9.         temp_posts = []
  10.         posts = []
  11.         for item in result:
  12.             temp_posts.append(item)
  13.             temp_posts.sort(key=lambda k: (k['post_time'][-5:]), reverse=True)
  14.         for item in temp_posts:
  15.             if item['post_day_time'] == cur_time:
  16.                 posts.append(item)
  17.         self.render(\"index.html\", info=posts, today=cur_time)

由于名字要和前端一一对应,所以,前端的代码如下:

  1. <body>
  2. <h1>技术讨论  {{today}}</h1>
  3. {% for element in info %}
  4. <div class=\"post_block\">
  5.   <p class=\"post_id\">{{element['post_id']}}</p>
  6.       <a class=\"post_url\" href=\"{{element['post_url']}}\" data-url=\"{{element['post_url']}}\" target=\"_blank\">{{element['post_title']}}</a>
  7.   <p class=\"post_time\">{{element['post_time']}}</p>
  8. </div>
  9. {% end %}
  10. </body>

注意,后端传过来的today对应的html里面的{{today}},info则对应的for循环里面的info。这种for循环,语法有点像DoT.js。别慌,这种前端的写法就那么几种,并不是很难,看懂例子怎么写,就照猫画虎的往自己的html里面写就可以。

看到了吗,就是这么简单,最后我们运行起来,效果如下:

用Tornado来实现你的服务器梦想,Python编程纯干货教学

404页面的处理:

处理404页面,只需要在main.py文件的url中,加入一个(r".*", BaseHandle),然后在BaseHandler里面,返回一个你已经写好的404.html就好了。炒鸡简单。

最后很关键的,怎么跑起来程序!
最后,代码写好了,我们需要把我们的程序跑起来。

首先,将你的工程部署到你的服务器上,通过前文所讲的部署方法,成功传上去文件。

然后,登录到你的服务器,进入工程指定的文件夹。

由于我们的启动程序是在main.py里面写的,所以,这里只需要输入指令:

  1. # sudo python main.py &

1就可以让你的Tornado后台运行了!千万别忘了后面还有个&。

如果要关闭你的运行程序,则需要输入:

  1. # ps -ef | grep main.py

来查找你Tornado所在的进程,通过kill指令关闭就可。

  1. # kill -9 <进程号>

后记不后记

看到没有,这样就可以了。一个例子虽然很简单,但是这里可以扩展的地方有很多。很多同学肯定苦恼于不知道该怎么写服务端的代码,那么这篇文章所讲的东西可以很好的带你入门,并且入门还前进了一小步,因为并不是简简单单的只给你写hello world。

前面还提到了可以用Tornado来定时执行任务,这个东西我就不再这里说了,如果想更多交流的话,大家可以私信我。由于账号等级有限,可能不能第一时间回复您的信息,请见谅。

这些所讲的内容的代码,我也给大家共享出来:

链接: https://pan.baidu.com/s/1MIFYRbYORX1sqE6B1N440Q

密码: bmr4

图片引用自网络