美文网首页
使用flask快速撸一个http在线请求工具

使用flask快速撸一个http在线请求工具

作者: Code人生 | 来源:发表于2019-07-09 23:14 被阅读0次

    好久没有使用python flask 框架了,今天有个想法,就是打造自己的一个在线http请求工具,网上有很多这样的工具,写这个东西本身没有太多的技术含量,纯粹是为了学习,顺便巩固一下flask。
    话不多说先看效果


    image.png
    image.png
    image.png

    看上去很简单,觉得就是个表单提交,实际上呢,也是需要一点处理逻辑的,麻雀虽小,五张俱全嘛。因为这个demo不需要数据库,也不需要管理,所以,采用flask开发在合适不过了。废话说完了,开始撸码,真刀真枪开始干。

    实现思路: 前端使用ajax提交表单到后台,后台通过requests 进行http请求并返回结果,然后将结果返回给前端进行展示,就是这么简单。

    第一步:环境准备:
    1.python3.x
    2.flask web框架
    3.requests http请求框架
    4.bootstrap 框架(界面)
    5.pycharm 开发工具

    第二步: 基本项目搭建
    1.用pycharm新建一个flask项目,然后跑起来,这一步是为了验证项目是否有问题。
    2.在项目的templates目录新建一个html文件,然后修改flask后台代码返回新建的html模版看能否正常显示

    from flask import render_template 
    @app.route('/')
    def home():
        return render_template('index.html')
    

    3.修改html文件,引入bootstrap,完成基本的页面布局

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>http在线工具</title>
    
        <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    
    <div class="col-sm-12" style="margin-top: 20px">
    
       <div class="col-sm-6">
        <form role="form">
      <div class="form-group">
        <label for="name">请求地址:</label>
        <input type="text" class="form-control" id="url" placeholder="http://或https://">
      </div>
       <div class="form-group">
        <label for="name">请求方式:</label>
        <select class="form-control" id="method">
          <option value="get" selected>get</option>
          <option value="post">post</option>
        </select>
      </div>
         <div class="form-group">
        <label for="name">请求头信息:</label>
        <textarea class="form-control" id="headers" rows="3" placeholder="如:token:xxxx,a:xx多个参数用,隔开"></textarea>
      </div>
         <div class="form-group">
          <label for="name">请求参数:</label>
        <textarea class="form-control" rows="3" id="params" placeholder="如:a=1&b=2"></textarea>
      </div>
    
            <button  id="btn" class="btn btn-primary" data-loading-text="Loading..."
        type="button"> 提交
    </button>
    </form>
    </div>
    
    
    <div class="col-sm-6">
    
        <ul class="nav nav-tabs" id="tabs">
      <li class="active"><a href="#">格式化响应</a></li>
      <li><a href="#">原始响应</a></li>
      <li><a href="#">响应头信息</a></li>
    
    </ul>
    
     <textarea id="result" style="margin-top: 10px;overflow: scroll;padding:10px;background-color:cornsilk;width: 100%;height: 350px">
    
     </textarea>
    </div>
    </div>
       
    </body>
    </html>
    

    4.重新启动项目看看界面效果是否正常,没有问题。
    5.在app.py里新增一个函数用户接收前端发来的参数

    @app.route("/http", methods=['post'])
    def http_request():
    return "请求成功"
    

    6.在前端页面用jquery进行ajax请求:

      $.ajax(({
                url:'/http',
                method:'post',
                success:function(data){
                    alert(data)
    
                },
                error:function (e) {
                
                    alert("请求地址异常")
                }
            }))
    

    如果可以正常的请求,基本的环境就搭建完成了。

    第三步,逻辑的实现:
    1.分析前端需要传哪些参数到后台,首先请求地址url、然后请求方式,method,还是请求头信息headers和请求参数信息params。前端获取输入的这些值,基础的就不多说了。
    2.ajax请求添加这些参数

        $.ajax({
    
                url:'/http',
                method:'post',
                data:{url:url,method:method,headers:headers,params:params},
                success:function(data){
      
                    response = data.body;
                    header = data.header;
                    show(response);
    
                },
                error:function (e) {
        
                    alert("请求地址异常")
                }
    
            })
    
    1. 修改后台函数后台进行参数接收:
    @app.route("/http", methods=['post'])
    def http_request():
        url = request.form['url']
        print('----url----',url)
        method = request.form['method']
        print('----method----',method)
        headers = request.form['headers']
        print('----headers----',headers)
        params = request.form['params']
        print('----params----',params)
        return "请求成功"
    

    在前端提交看看后台能不能收到这些参数,如果不会flask参数接收自行到网上搜索一下。收到了参数就进行下一步。

    4.处理接收到的参数,因为requests需要的参数不是字符串,所以需要转换成一个字典。第一个就是处理请求头信息,新增一个函数用户处理头信息:

    def parse_headers(headers):
        args = {}
        if headers:
            sps = headers.split(',')
            for s in sps:
                p = s.split(":")
                print(p[0], "=", p[1])
                args[p[0]] = p[1]
    
        return args
    

    这里需要前段端和后台的参数约束,比如:多个参数用,号隔开,键和值之间用:,处理完成返回一个字典。

    第二个就是处理请求参数的函数:

    def parse_params(params):
        args = {}
        if params:
            sps = params.split('&')
            for s in sps:
                p = s.split("=")
                print(p[0], "=", p[1])
                args[p[0]] = p[1]
    
        return args
    

    和请求头信息处理类似,只是约束不一样,我们多个参数使用&链接,键和值用=号。

    5.使用requests进行http请求,一般都是使用

    import requests
    一般都是使用
    requests.get()和requests.post;
    

    但是为了统一采用以下方式进行请求,不清楚的可以看requests的相关文档:

    from requests import Session, Request
    # 统一发起http请求
    def send(url, method, headers, data):
        s = Session()
        req = Request(method, url,
                      data=data,
                      params=data,
                      headers=headers
                      )
        prepped = req.prepare()
        resp = s.send(prepped)
        try:
            res = {"header": "{0}".format(resp.headers), "body": "{0}".format(resp.content.decode(encoding='utf-8'))}
            return Response(json.dumps(res), mimetype='application/json')
        except:
            res = {"header": "{0}".format(resp.headers), "body": "{0}".format(resp.content)}
            return Response(json.dumps(res), mimetype='application/json')
    
    

    这里面有个data和params参数,说明一下,为什么要传两个,data参数是针对post请求的params是get请求,因为这里的请求既支持get也支持post请求,这两个参数都传是为了保证post和get请求都能把参数传输过去。请求成功后,返回json给前端。我们要返回headr和body,因为前端需要展示请求头信息和请求内容。这里需要注意的是得到的header信息和请求的content信息不能直接被序列化,所以需要转换成字符串在以json的格式输出,否则就会报错,因为转了字符串,导致编码问题,所以需要用decode解码,但是解码的时候有些内容不支持utf-8,会产生异常,因此需要进行异常处理,保证把结果返回。

    1. 后台调用:修改http_request函数
    @app.route("/http", methods=['post'])
    def http_request():
        url = request.form['url']
        method = request.form['method']
        headers = parse_headers(request.form['headers'])
        params = request.form['params']
        args = parse_params(params)
    
        return send(url, method, headers, args)
    

    当然,还有需要完善的地方,比如参数校验,我就偷懒不处理了😂。

    7.前端的展示

         $.ajax({
    
                url:'/http',
                method:'post',
                data:{url:url,method:method,headers:headers,params:params},
                success:function(data){
            
                    response = data.body;
                    header = data.header;
                    show(response);
    
                },
                error:function (e) {
             
                    alert("请求地址异常")
                }
    
            })
    
        //tab切换
         $('#tabs li').click(function () {
    
    
              $.each($('#tabs li'),function (i,item) {
                    item.className = '';
              })
    
              this.className = 'active';
    
    
             switch ($(this).index()) {
    
                 case 0:
                     //展示格式化结果
                      show(response)
                     break;
                 case 1:
                     //展示原始结果
                       $('#result').val(response);
                     break;
    
                 case 2:
                     //展示响应头信息
                      show(header)
                     break;
    
             }
    
    
         })
    
          //展示请求结果
           function show(data) {
    
              try{
                     var json = formatJson(data)
                         $('#result').val(json);
                    }catch (e) {
    
                       $('#result').val(data);
                    }
           }
           //格式化json
           function formatJson(json, options) {
                        var reg = null,
                            formatted = '',
                            pad = 0,
                            PADDING = '    '; // one can also use '\t' or a different number of spaces
                        // optional settings
                        options = options || {};
                        // remove newline where '{' or '[' follows ':'
                        options.newlineAfterColonIfBeforeBraceOrBracket = (options.newlineAfterColonIfBeforeBraceOrBracket === true) ? true : false;
                        // use a space after a colon
                        options.spaceAfterColon = (options.spaceAfterColon === false) ? false : true;
    
                        // begin formatting...
    
                        // make sure we start with the JSON as a string
                        if (typeof json !== 'string') {
                            json = JSON.stringify(json);
                        }
                        // parse and stringify in order to remove extra whitespace
                        json = JSON.parse(json);
                        json = JSON.stringify(json);
    
                        // add newline before and after curly braces
                        reg = /([\{\}])/g;
                        json = json.replace(reg, '\r\n$1\r\n');
    
                        // add newline before and after square brackets
                        reg = /([\[\]])/g;
                        json = json.replace(reg, '\r\n$1\r\n');
    
                        // add newline after comma
                        reg = /(\,)/g;
                        json = json.replace(reg, '$1\r\n');
    
                        // remove multiple newlines
                        reg = /(\r\n\r\n)/g;
                        json = json.replace(reg, '\r\n');
    
                        // remove newlines before commas
                        reg = /\r\n\,/g;
                        json = json.replace(reg, ',');
    
                        // optional formatting...
                        if (!options.newlineAfterColonIfBeforeBraceOrBracket) {
                            reg = /\:\r\n\{/g;
                            json = json.replace(reg, ':{');
                            reg = /\:\r\n\[/g;
                            json = json.replace(reg, ':[');
                        }
                        if (options.spaceAfterColon) {
                            reg = /\:/g;
                            json = json.replace(reg, ': ');
                        }
    
                        $.each(json.split('\r\n'), function(index, node) {
                            var i = 0,
                                indent = 0,
                                padding = '';
    
                            if (node.match(/\{$/) || node.match(/\[$/)) {
                                indent = 1;
                            } else if (node.match(/\}/) || node.match(/\]/)) {
                                if (pad !== 0) {
                                    pad -= 1;
                                }
                            } else {
                                indent = 0;
                            }
    
                            for (i = 0; i < pad; i++) {
                                padding += PADDING;
                            }
                            formatted += padding + node + '\r\n';
                            pad += indent;
                        });
                        return formatted;
                    };
    

    这里需要注意,结果的展示不要使用div,就使用textarea,不然josn格式化不会有效果。

    第四步:测试
    万事具备了,就来测试一把,如果有什么错误就调试一下代码了。

    下面贴一下完整代码:前端,html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>http在线工具</title>
    
        <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    
    <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
    
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    </head>
    <body>
    
    <div class="col-sm-12" style="margin-top: 20px">
    
       <div class="col-sm-6">
        <form role="form">
      <div class="form-group">
        <label for="name">请求地址:</label>
        <input type="text" class="form-control" id="url" placeholder="http://或https://">
      </div>
       <div class="form-group">
        <label for="name">请求方式:</label>
        <select class="form-control" id="method">
          <option value="get" selected>get</option>
          <option value="post">post</option>
        </select>
      </div>
         <div class="form-group">
        <label for="name">请求头信息:</label>
        <textarea class="form-control" id="headers" rows="3" placeholder="如:token:xxxx,a:xx多个参数用,隔开"></textarea>
      </div>
         <div class="form-group">
          <label for="name">请求参数:</label>
        <textarea class="form-control" rows="3" id="params" placeholder="如:a=1&b=2"></textarea>
      </div>
     
            <button  id="btn" class="btn btn-primary" data-loading-text="Loading..."
        type="button"> 提交
    </button>
    </form>
    </div>
    
    
    <div class="col-sm-6">
    
        <ul class="nav nav-tabs" id="tabs">
      <li class="active"><a href="#">格式化响应</a></li>
      <li><a href="#">原始响应</a></li>
      <li><a href="#">响应头信息</a></li>
    
    </ul>
    
     <textarea id="result" style="margin-top: 10px;overflow: scroll;padding:10px;background-color:cornsilk;width: 100%;height: 350px">
    
     </textarea>
    
    
    
    </div>
    </div>
    
    
    <script>
    
         var method = 'get';
         var response='';
         var header = '';
        $('#method').change(function () {
    
            method=$("#method").val();
    
        })
    
        $('#btn').click(function () {
    
            var url = $('#url').val();
            var headers = $('#headers').val();
            var params = $('#params').val();
    
            if(url==null||url.length==0){
    
                alert("请求地址不能为空")
                return;
            }
            if(!url.startsWith("http://")&&!url.startsWith("https://")){
    
                alert("请求地址有误")
                return;
            }
            $(this).button('loading');
    
            $.ajax({
    
                url:'/http',
                method:'post',
                data:{url:url,method:method,headers:headers,params:params},
                success:function(data){
                    $('#btn').button('reset');
                    response = data.body;
                    header = data.header;
                    show(response);
    
                },
                error:function (e) {
                   $('#btn').button('reset');
                    alert("请求地址异常")
                }
    
            })
    
    
        })
    
    
         //tab切换
         $('#tabs li').click(function () {
    
    
              $.each($('#tabs li'),function (i,item) {
                    item.className = '';
              })
    
              this.className = 'active';
    
    
             switch ($(this).index()) {
    
                 case 0:
                     //展示格式化结果
                      show(response)
                     break;
                 case 1:
                     //展示原始结果
                       $('#result').val(response);
                     break;
    
                 case 2:
                     //展示响应头信息
                      show(header)
                     break;
    
             }
    
    
         })
    
          //展示请求结果
           function show(data) {
    
              try{
                     var json = formatJson(data)
                         $('#result').val(json);
                    }catch (e) {
    
                       $('#result').val(data);
                    }
           }
           //格式化json
           function formatJson(json, options) {
                        var reg = null,
                            formatted = '',
                            pad = 0,
                            PADDING = '    '; // one can also use '\t' or a different number of spaces
                        // optional settings
                        options = options || {};
                        // remove newline where '{' or '[' follows ':'
                        options.newlineAfterColonIfBeforeBraceOrBracket = (options.newlineAfterColonIfBeforeBraceOrBracket === true) ? true : false;
                        // use a space after a colon
                        options.spaceAfterColon = (options.spaceAfterColon === false) ? false : true;
    
                        // begin formatting...
    
                        // make sure we start with the JSON as a string
                        if (typeof json !== 'string') {
                            json = JSON.stringify(json);
                        }
                        // parse and stringify in order to remove extra whitespace
                        json = JSON.parse(json);
                        json = JSON.stringify(json);
    
                        // add newline before and after curly braces
                        reg = /([\{\}])/g;
                        json = json.replace(reg, '\r\n$1\r\n');
    
                        // add newline before and after square brackets
                        reg = /([\[\]])/g;
                        json = json.replace(reg, '\r\n$1\r\n');
    
                        // add newline after comma
                        reg = /(\,)/g;
                        json = json.replace(reg, '$1\r\n');
    
                        // remove multiple newlines
                        reg = /(\r\n\r\n)/g;
                        json = json.replace(reg, '\r\n');
    
                        // remove newlines before commas
                        reg = /\r\n\,/g;
                        json = json.replace(reg, ',');
    
                        // optional formatting...
                        if (!options.newlineAfterColonIfBeforeBraceOrBracket) {
                            reg = /\:\r\n\{/g;
                            json = json.replace(reg, ':{');
                            reg = /\:\r\n\[/g;
                            json = json.replace(reg, ':[');
                        }
                        if (options.spaceAfterColon) {
                            reg = /\:/g;
                            json = json.replace(reg, ': ');
                        }
    
                        $.each(json.split('\r\n'), function(index, node) {
                            var i = 0,
                                indent = 0,
                                padding = '';
    
                            if (node.match(/\{$/) || node.match(/\[$/)) {
                                indent = 1;
                            } else if (node.match(/\}/) || node.match(/\]/)) {
                                if (pad !== 0) {
                                    pad -= 1;
                                }
                            } else {
                                indent = 0;
                            }
    
                            for (i = 0; i < pad; i++) {
                                padding += PADDING;
                            }
                            formatted += padding + node + '\r\n';
                            pad += indent;
                        });
                        return formatted;
                    };
    
    
    </script>
    </body>
    </html>
    

    后台:app.py

    from flask import Flask, request, Response
    from flask import render_template
    from requests import Session, Request
    import json
    
    app = Flask(__name__)
    
    
    # 页面展示
    @app.route('/')
    def home():
        return render_template('index.html')
    
    
    # 处理http请求
    @app.route("/http", methods=['post'])
    def http_request():
        url = request.form['url']
        method = request.form['method']
        headers = parse_headers(request.form['headers'])
        params = request.form['params']
        args = parse_params(params)
    
        return send(url, method, headers, args)
    
    
    # 统一发起http请求
    def send(url, method, headers, data):
        s = Session()
        req = Request(method, url,
                      data=data,
                      params=data,
                      headers=headers
                      )
        prepped = req.prepare()
        resp = s.send(prepped)
        try:
            res = {"header": "{0}".format(resp.headers), "body": "{0}".format(resp.content.decode(encoding='utf-8'))}
            return Response(json.dumps(res), mimetype='application/json')
        except:
            res = {"header": "{0}".format(resp.headers), "body": "{0}".format(resp.content)}
            return Response(json.dumps(res), mimetype='application/json')
    
    
    # 处理请求参数转换成字典
    def parse_params(params):
        args = {}
        if params:
            sps = params.split('&')
            for s in sps:
                p = s.split("=")
                print(p[0], "=", p[1])
                args[p[0]] = p[1]
    
        return args
    
    
    # 处理请求头信息转换成字典
    def parse_headers(headers):
        args = {}
        if headers:
            sps = headers.split(',')
            for s in sps:
                p = s.split(":")
                print(p[0], "=", p[1])
                args[p[0]] = p[1]
    
        return args
    
    
    # 用于测试参数的接收和头信息的接收
    @app.route('/test', methods=['get', 'post'])
    def test():
        if request.method == 'GET':
            a = request.args.get('a', '')
            b = request.args.get('b', '')
            token = request.headers.get('token')
            return '测试get请求,参数 a={0},b={1},头:token={2}'.format(a, b, token)
    
        a = request.form['a']
        b = request.form['b']
        token = request.headers.get('token')
    
        return '测试post请求,参数 a={0},b={1},头:token={2}'.format(a, b, token)
    
    
    if __name__ == '__main__':
        app.run()
    

    第五步:总结
    到这里,使用flask撸一个http在线请求工具就完成了,当然这只是实现一个模拟过程,还需要做一些细节优化,废话多了,只是想说的详细点。因为代码不多我就不上传到github了,如果有需要的可以联系我,如果有问题欢迎留言讨论,喜欢我的文章记得关注我😊哦!

    相关文章

      网友评论

          本文标题:使用flask快速撸一个http在线请求工具

          本文链接:https://www.haomeiwen.com/subject/xvtqkctx.html