前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python - 本地mocker服务

python - 本地mocker服务

作者头像
千往
发布2020-06-18 16:16:40
5010
发布2020-06-18 16:16:40
举报

本地mocker服务

技术选型

python3 + http.server

流程

  1. 获取请求
  2. 通过请求的path,params(query_params+body_params),method去匹配对应的response
    1. 本地的response需要事先设置好
  3. 将response返回

代码

#!/usr/bin/python
# coding=utf-8


import os
import re
import threading
import time
import logging
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
from urllib.parse import urlparse, parse_qs, urlsplit


class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.end_headers()

    def _respond(self):

        path = self.path
        self._set_headers()
        response = self._mock_content(path)
        if isinstance(response, str):
            response = str.encode(response)

        self.wfile.write(response if response else '')

    def do_HEAD(self):
        self._set_headers()

    def do_GET(self):
        self._respond()

    def do_POST(self):
        self._respond()

    def do_PUT(self):
        self._respond()

    def do_DELETE(self):
        self._respond()

    def _get_filename(self, code, format='json'):
        return "%s_%s.%s" % (self.command, code, format)

    def _mock_content(self, url_path):

        # 记录请求的参数
        query_dict, body_dict = self.save_query_body(url_path)

        # 根据url_path来匹配content_path
        content_path = self.get_content_path()
        rep = self.get_mock_response(url_path, content_path)
        return rep

    def get_content_path(self):
        http_method = self.command
        json_name = "/" + http_method + "_200.json"
        pre_dirname = "../mocker_response"
        file_name = pre_dirname + urlsplit(self.path).path + json_name

        if os.path.exists(file_name):
            return file_name
        else:
            return None

    def save_query_body(self, url_path):
        # 获取实际url query
        query = urlsplit(url_path).query

        query_dict = dict([(k, v[0]) for k, v in parse_qs(query).items()])
        # 获取实际url body
        content_len = int(self.headers.get('content-length', 0))
        body = self.rfile.read(content_len)

        body_dict = dict([(k, v[0]) for k, v in parse_qs(body.decode('utf-8')).items()])

        # 写入 MOCK_REQUEST
        MOCK_REQUEST = {}
        path = re.sub("/{1,}", "", urlparse(url_path).path, count=1)
        MOCK_REQUEST[path] = {}
        MOCK_REQUEST[path]['query'] = query_dict
        MOCK_REQUEST[path]['body'] = body_dict

        print(MOCK_REQUEST)

        return query_dict, body_dict

    @staticmethod
    def get_mock_response(url_path, content_path):
        rep = ''
        if content_path is None:
            logging.warning("can NOT find the response. please check.")
            return '{"code":404, "msg":"can NOT find the response. please check."}'

        # 读取整个文件
        with open(content_path, 'r+') as f:
            for line in f:
                rep += line

        # 内容为空
        if not rep:
            logging.warning("empty file for path: %s" % url_path)
            rep = "{'code':400, 'msg':'empty file for path: %s'}" % url_path

        return rep


class ThreadingHttpServer(ThreadingMixIn, HTTPServer):
    # 多线程
    pass


class Mocker(threading.Thread):

    def __init__(self, address, port, dir):
        """
        :param address: server 地址
        :param port: 端口
        :param dir: mock文件地址
        """
        threading.Thread.__init__(self)

        server_class = ThreadingHttpServer
        self.httpd = server_class((address, port), S)

    def run(self):
        try:
            self.httpd.serve_forever()
        except Exception as e:
            logging.error(e)
            self.mock_stop()

    def mock_start(self):
        print('Starting  mock server...')
        self.start()

    def mock_stop(self):
        print('Stopping  mock server...')
        self.httpd.shutdown()
        self.httpd.server_close()


# test
if __name__ == '__main__':
    dsp = Mocker('127.0.0.1', 8099, '')
    dsp.mock_start()
    while True:
        try:
            time.sleep(1)
            print("wait")
        except(KeyboardInterrupt) as e:
            dsp.mock_stop()

代码解析

核心模块是http.server 官方文档: https://docs.python.org/zh-cn/3/library/http.server.html 需要自己自定义一个requestHandler,就是在这里处理mocker的核心服务代码

备注

  1. 看官方文档,在python3.7+后就支持**ThreadingHTTPServer **了,不需要自己去继承ThreadingMixIn了的 ,后续可以优化了的
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-06-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本地mocker服务
    • 技术选型
      • 流程
      • 代码
      • 代码解析
      • 备注
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档