zoukankan      html  css  js  c++  java
  • Nodejs/Jquery/Bootstrap搭建简单的web服务

    Nodejs/Jquery/Bootstrap搭建简单的web服务

    Contents

    最近想给毕设加入一个前端界面来调用后台的一些功能,这样展示性更好。我使用BootStrap,Jquery写了一个很简陋的前端界面。服务器端使用Node.js express框架开了接口。之前以为是挺简单的一个东西,因为这些代码网上应该有很多可以参考。然而这个过程中,踩了不少的坑,花了3天时间,才把基本流程调通...记录一下我踩过的坑。

    整体思路

    • 我的需求是:
      调用后台的Nodejs接口,进行增删查改操作,并向前端返回操作结果。由于我对于前后端的了解非常的肤浅,所以就选择了自己听说过的几个框架来写:

      • 后端用Nodejs Express开接口
      • 前端用Bootstrap,Jquery实现基本逻辑
    • 代码实现:
      那么根据我的需求,参考了一系列教程/博客,我抄来写的代码如下

    1. Nodejs端
    var express = require('express');
    var path = require('path')
    var bodyParser = require('body-parser');
    
    var app = express();
    app.use(bodyParser.urlencoded({extended : false}));//这是一个中间件,用于解析请求内容
    
    var SaveData = require("./SaveData.js");
    var OffChainDB = require("./OffChainDB.js");
    
    app.use(express.static(path.join(__dirname, '../privacy_frontend')));//设置静态文件中间件,在../privacy_frontend下包含我的前端html文件
    
    app.post('/savedata',function(request,response){
        console.log(request.body);//打印request的json内容
        
        var result = SaveData.SaveData();//调用接口,作用是向数据库插入数据,返回一个Promise对象,并携带着数据库返回的消息
        
        result.then(r => {
            console.log('success', r)
            str = JSON.stringify(r)
            response.json(str)
        }).catch(e => {
            console.log('error', e)
        })
    })
    
    var server = app.listen(3000,function(){//监听3000端口,这样浏览器直接访问IP:3000就可以访问到上面开的接口了
        var host = server.address().address;
        var port = server.address().port;
    
        console.log("app listening at port 3000");
    })
    
    process.on('unhandledRejection',function(err){//绑定对于unhandleRejection的回调函数,报错
        console.error(err.stack);
    });
    
    process.on('uncaughtException',console.error);//跟上一句类似
    
    1. 前端
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>保存数据</title>
        <link href="bootstrap.min.css" rel="stylesheet">
        <script src="jquery-3.4.0.min.js"></script>
        <script src="bootstrap.min.js"></script>
    </head>
    <body>
        <form class="form-horizontal">
            <div class="form-group">
                <label for="inputChaincode" class="col-sm-2 control-label">链码</label>
                <div class="col-sm-6">
                    <input type="text" class="form-control" id="inputChaincode" placeholder="链码">
                </div>
            </div>
            <div class="form-group">
                <label for="inputMethod" class="col-sm-2 control-label">链码方法</label>
                <div class="col-sm-6">
                    <input type="text" class="form-control" id="inputMethod" placeholder="链码方法">
                </div>
            </div>
            <div class="form-group">
                <label for="inputDataType" class="col-sm-2 control-label">数据类型</label>
                <div class="col-sm-6">
                    <input type="text" class="form-control" id="inputDataType" placeholder="插入数据类型">
                </div>
            </div>
            <div class="form-group">
                <label for="inputData" class="col-sm-2 control-label">数据</label>
                <div class="col-sm-6">
                    <input type="text" class="form-control" id="inputData" placeholder="数据">
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-2 col-sm-10">
                    <!-- <button type="submit" class="btn btn-default" id="btn_submit">保存数据</button> -->
                    <a type="submit" class="btn btn-default" id="btn_submit">保存数据</a>
                    <script>
                        var json = {};//对象类型的变量
                        $("#btn_submit").click(function () {
                            json['chaincode'] = $("#inputChaincode").val();//从表单的每一个输入框获取信息,拼接成一个json对象
                            json['method'] = $("#inputMethod").val();
                            json['datatype'] = $("#inputDataType").val();
                            json['data'] = $("#inputData").val();
                            alert(JSON.stringify(json));
    
                            $.post("http://192.168.253.130:3000/savedata",//向服务器发送post请求
                            json,//要发送的数据(request body)
                            function (data,status) {//成功收到消息的回调函数
                                alert("数据:
    "+data+"
    状态: "+status);//一系列弹窗提示
                                console.log(data);
                                console.log(status);
                                alert("callback is invoked!");
                                alert(data);
                            })
                        });
                    </script>
                </div>
            </div>
        </form>
    </body>
    </html>
    
    • 界面部分使用了bootstrap自带的表单样式,代码基本来源于官网文档。然而这就是坑的开始。
    • js脚本部分,也很简单。就是为提交按钮增加一个点击事件回调函数。回调函数内容就是向Nodejs后台发起post请求,等待回应。

    跨域访问问题

    • 之前听说过跨域访问这个名词,然而不知道具体是什么意思。这一次算是有了切身经验,理解了这个概念的含义。

    • 我的nodejs后端运行在我的虚拟机linux上,而前端最开始放在我的本地windows里(为了方便调试)。然后发现发出的post请求怎么也收不到。

    • 最后发现因为这是跨域请求。跨域请求的概念是:

      • 请求者和被请求者的 协议,ip,端口 中的任意一个不相同,就是跨域访问,js默认是不允许跨域访问的(出于安全考虑)。
      • 这一点在Jquery文档里也有写

      文档内容
      文档内容

    • 解决方法

      • 将前端界面也放到linux虚拟机上,跟后端使用同一IP:端口,就解决了跨域访问的问题
      • 这告诉我们,使用轮子之前一定要好好看文档啊。

    Jquery.post()回调函数不执行问题

    • 以上的第一个问题其实很快就发现了,然而第二个问题才是大坑。找了很久才发现问题所在。
    • 在上面的<script>脚本里边,调用了$.post()函数,看起来挺简单的,参考了一下菜鸟教程,然后就写好了。
      • 运行的现象
      • 后端能收到请求,也能发送响应。但是前端收到数据的回调函数怎么也不执行,浏览器F12调试也根本看不到发出的post请求。
      • 用postman进行请求,没有任何问题。
    • 然后就开始了漫长的找bug过程,由于没有任何报错信息,只能盲目的通过注释代码,修改代码来尝试。
      • 开始认为是后端的问题,因为尝试发现:如果不调用SaveData.SaveData()这个函数,而是直接给一个resolved的Promise,就没有问题。于是我各种修改SaveData()函数,将它由Promise写法改成了普通回调的写法。结果好像并没有什么用。
      • 然后怀疑是response.send()参数数据类型的问题。尝试发现:如果这个数据比较短,前端就能执行回调,否则就不行。是否能执行回调貌似变成了一个概率事件...要看运气的...这时候我已经绝望了,这是什么玄学问题,还从没遇到那么诡异的bug。
      • 绝望之后,再怀疑前端,把$post改成链式调用的方式,写了$.post().done().fail()函数来代替作为参数的回调函数。居然就成功了。稳定的能够执行回调函数。但是依然不知道为什么。
      • 直到看到StackOverflow上面的一个回答,问题与我类似;他说是因为他的前端会自动刷新,所以刷新过后,上一次执行script代码时创建的jqXHR对象就没有了,自然浏览器也看不到这个请求的消息,也不会执行回调函数。
      • 仔细观察我的前端运行,貌似的确每次点击提交按钮就会刷新一下页面,但是我并没有写这个逻辑啊...问题出在哪呢?只有可能是bootstrap,搜了一下发现点击按钮就刷新页面这个逻辑是bootstrap自带的,自带的....发现bootstrap才是罪魁祸首,欲哭无泪啊...从始至终就没有注意到这一点。
      • 解决方法:
        • 参考了这一篇博文
        • 修改了<button>标签为<a>标签,问题解决。跟nodejs后端,跟jquery.post()没有任何关系emmmmm....
        • 以上经验告诉我们:用轮子的时候看文档也不一定管用啊...bootstrap文档里没有告诉我点击button会自动刷新的啊...

    总结

    • 回顾整个过程,还是能学到一些经验
      • VSCode用作Nodejs的调试工具非常好用,能用调试器就不要用打印日志这种办法了,效率极低。
      • 当你对一些语法类的东西不确定的时候,一个简单的方法是:跳出复杂的场景,自己重新写一个test.js来测试各种情况。比如我对promise的状态改变,执行流程搞不清楚,那么就写一个test的代码来各种尝试,这样很快就能弄清楚一些模糊的地方。
      • Postman如果测试没问题,那么后端的接口就一定是没问题的。我并没有意识到这一点,将注意力放在了后端上。其实是南辕北辙了。一开始就定位问题在前端,可能就没有那么费劲了。
      • 用轮子之前,尽量还是把一些注意事项,文档通读一遍,直接上来就怼代码可能事倍功半。
  • 相关阅读:
    redis的其他命令
    redis的有序集合ZSET(stored set)
    redis 的set数据类型
    redis 的hash数据类型
    php命令
    intellij idea
    生产者消费者问题
    JAVA sleep和wait 异同
    JAVA线程通信
    java线程同步--lock锁(JDK 5 新增)
  • 原文地址:https://www.cnblogs.com/Howfars/p/10734379.html
Copyright © 2011-2022 走看看