当前位置:首页 > CN2资讯 > 正文内容

python 网关服务器 python做服务器接口

22小时前CN2资讯


接到个小活,要实现一个局域网内的小服务器,需求如下:

1.实现静态文件下发功能,主要是apk安装包和html及其相关文件;

2.实现数据接口,用于存储和查询网内其他设备发来的数据;

3.实际使用者电脑能力一般,环境搭建和操作越简单越好。

最近在学Python,正好来练练手。话不多说,开搞!

开发环境:Windows7 + Python3.5.2


第一步,当然是要把服务器跑起来啦!


查了下原来超级简单,只要用命令行进入想作为服务器目录的目录,并运行如下命令:


python -m SimpleHTTPServer 8000


结果报了错:No module named SimpleHTTPServer,什么情况?

查了下这个错误,原来SimpleHTTPServer是Python 2.X的模块,3.X中需要用http.server,于是修改如下:


python -m http.server 8080


运行后提示:

再打开浏览器,访问http://127.0.0.1:8000/

果然看到了目录的文件列表。

在服务器目录里随便丢了个index.html,浏览器访问http://127.0.0.1:8000/index.html:

成功!


第二步,用Python代码跑服务器


命令行一句话的事,用代码当然也很简单:


import http.server as hs httpAddress = ('', 8000) httpd = hs.HTTPServer(httpAddress, RequestHandler) httpd.serve_forever()


其中httpAddress为(url, port)的格式,url为空表示指向本机默认地址127.0.0.1,8000是端口号,改成其他未被占用的也可以。

那么RequestHandler是什么呢?


第三步,实现RequestHandler


RequestHandler其实是对http.server.BaseHTTPRequestHandler这个基础类的继承,即对http请求的响应。但它本身不包含任何方法,需要自行实现。

项目中没有用到post请求,因此只需实现do_GET方法:


import os import http.server as hs class RequestHandler(hs.BaseHTTPRequestHandler): def do_GET(self): self.full_path = os.getcwd() + self.path print(self.path) print(self.full_path) pass httpAddress = ('', 8000) httpd = hs.HTTPServer(httpAddress, RequestHandler) httpd.serve_forever()


其中self.path为请求的相对路径,os.getcwd()可以获取当前的工作目录。两者结合,便得到了请求目标在本机文件系统中的绝对路径。


运行程序,浏览器访问http://127.0.0.1:8000/index.html,果然看到了print的输出:



成功!



第四步,区分请求类型


获取访问地址后,当然是根据后缀名区分请求类型并各自处理咯。

结合需求和逻辑,服务器需要依照先后顺序判断并处理以下几类:

1.请求的文件不存在时,抛回错误页面并提示错误原因;

2.请求指向某个数据接口时,执行指定的python脚本并返回结果;

3.请求指向某个文件时,返回该文件;

4.以上情况皆不符合,抛回错误页面并提示错误原因。

项目中对这些请求分别建立包含test和act两个方法的类并一次调用,类似于:


cases = [case1(), case2(), case3(), case4()] for case in cases: if case.test(self): case.act(self) break


接下来就是实现每种请求的处理啦!以下几个是重点:


第五步,请求指定文件


前面已经拿到了请求文件的绝对地址,通过文件IO方法即可判断目标文件是否存在。

若文件存在,则读取文件内容并写入请求文件对象(通过self.wfile获取),对终端来说即是返回了该文件。

html文件里通常会包含css、js、图片、音频等各种引用,但实际访问时浏览器会自动对其所有引用文件单独发起get请求,所以服务器这边无需特殊对待,当做数个独立的文件请求来处理就行。

但是要注意,如果地址是类似url?param1=value1&param2=value2的形式,判断和返回文件内容时需要先把后面的参数部分截掉。代码如下:


def handle_file(self, full_path): try: #处理过程中需先截掉参数,否则会判断为文件不存在 full_path = full_path.split("?") full_path = full_path[0] #判断文件类型以设置mimetype mimetype = "" if self.path.endswith(".html"): mimetype='text/html' if self.path.endswith(".jpg"): mimetype='image/jpg' if self.path.endswith(".png"): mimetype='image/png' if self.path.endswith(".gif"): mimetype='image/gif' if self.path.endswith(".js"): mimetype='application/javascript' if self.path.endswith(".css"): mimetype='text/css' if self.path.endswith(".apk"): mimetype='application/vnd.android.package-archive' self.send_response(200) self.send_header('Content-type', mimetype) self.end_headers() with open(full_path, 'rb') as f: self.wfile.write(f.read()) except IOError as msg: msg = "'{0}' cannot be read: {1}".format(self.path, msg) self.handle_error(msg)


假如用到了其他类型文件,从网上找到对应的mimetype加进去就好。

往文件夹里丢了张小图片,试着访问下:

再试试访问下包含这个文件的页面:

成功!


第六步,请求数据接口


数据接口的实现思路也很简单:

1.服务器上准备好所需的python脚本,对应不同数据接口的功能

2.终端直接以url+参数的形式访问数据接口(即对应的Python脚本);

3.服务器判断出这种情况后,执行该Python脚本并传入参数;

4.Python脚本被执行,根据参数对目标文件(或数据库)进行增删改查等操作;

5.Python脚本的执行结果以文本方式传回,作为本次数据请求的回调。


import argparse try: parser = argparse.ArgumentParser(description='manual to this script') parser.add_argument('--id', type = int, default = -1) parser.add_argument('--name', type = str, default = None) args = parser.parse_args() if < 0: print('{"result":"False","msg":"invalid id"}') else: id = name = name = name.encode(encoding = "utf-8") print('{"result":"True","id":"%d","name":"%s"}' %(id, name)) except BaseException as e: print('{"result":"False","msg":"%s"}' %str(e))


其中,脚本调用是通过subprocess.check_output()方法实现的。该方法会创建一个子进程以命令行方式执行指定的指令或脚本,父进程会等待其执行完毕并返回输出结果。

为了与传统接口形式统一,项目中的http请求参数是以?param1=value1&param2=value2的形式传递的;但调用Python脚本时,参数需要以--param1=value1{空格}--param2=value2……的形式传递,因此需要对其进行转换。

实现以上功能的代码如下:


def run_cgi(self, fullpath): #运行脚本并得到格式化的输出 #参数以url?param1=1¶m2=2……的方式传递 path = fullpath.split("?") if len(path) > 1: params = path[1] params = params.split("&") shell = [] shell.append("python") shell.append(path[0]) for param in params: shell.append("--" + param) data = subprocess.check_output(shell) else: data = subprocess.check_output(["python", path[0]]) self.send_content(page = str(data, encoding = 'utf-8'))


最后一行send_content方法的功能是返回纯文本作为请求结果,其实就是一个mimetype为text/html的文件输出:


def send_content(self, page, status = 200): self.send_response(status) self.send_header("Content-type", 'text/html') self.end_headers() self.wfile.write(bytes(page, encoding = 'utf-8'))


附上示例脚本:

import argparse try: parser = argparse.ArgumentParser(description='manual to this script') parser.add_argument('--id', type = int, default = -1) parser.add_argument('--name', type = str, default = None) args = parser.parse_args() if < 0: print('{"result":"False","msg":"invalid id"}') else: id = name = name = name.encode(encoding = "utf-8") print('{"result":"True","id":"%d","name":"%s"}' %(id, name)) except BaseException as e: print('{"result":"False","msg":"%s"}' %str(e))


可见:


1. 参数使用argparse库中的方法即可获取;


2. 脚本中通过print输出的内容即为脚本的返回内容;


3. 返回结果的中文内容建议进行urf-8转码并在终端转回,否则传输过程中容易遇到各种奇奇怪怪的问题。

打开浏览器,访问该脚本并传入参数:

成功!


第七步,异常处理


经过上面几个步骤,服务功能基本搭得差不多了。剩下的就是处理下异常情况,即生成一个包含错误内容的html页面:


Error_Page = """ <html> <meta http-equiv="content-type" content="text/html;charset=UTF-8" /> <body> <h1>Error accessing {path}</h1> <p>{msg}</p> </body> </html> """


访问个空地址试一试:

成功!

至此,全部功能完成。鞠躬。


    你可能想看:

    扫描二维码推送至手机访问。

    版权声明:本文由皇冠云发布,如需转载请注明出处。

    本文链接:https://www.idchg.com/info/23781.html

    分享给朋友:

    “python 网关服务器 python做服务器接口” 的相关文章