0

0

Nodejs的form验证及图片上传

php中世界最好的语言

php中世界最好的语言

发布时间:2018-03-16 13:52:13

|

1574人浏览过

|

来源于php中文网

原创

这次给大家带来Nodejs的form验证及图片上传 ,使用Nodejs的form验证及图片上传注意事项有哪些,下面就是实战案例,一起来看一下。

一、form验证

 MVC的form验证有三个地方可以做,第一道关就是前端提交之前,第二道关就是在数据保存之前,也就是在controller中做验证,第三道关就是数据保存的时候,也就是如果提交的数据模型不符合实体定义的约束,数据是无法保存的,这是最后一道防线。第一道关主要是依赖于js或者jquery框架,比较常用的是jquery.validate.js。如果是Asp.net MVC 可以自动生成验证规则,这里就不细究了,网上有很多文章。第二层和各自的业务逻辑有关,也需要做一些必要验证,防止前端禁止JavaScript,而提交不合法数据,这里是要讲基于Mongoose的第三层验证。

1.回顾模型定义

我们先回顾一下之前用Mongoose定义的book模型:

var bookSchema = new mongoose.Schema({
    title: { type: String, required: true },
    rating: {
        type: Number,
        required: true,
        min: 0,
        max: 5
    },
    info: { type: String, required: true },
    img: String,
    tags: [String],
    brief: { type: String, required: true },
    ISBN: String,
});

每个属性定义了类型和是否必须,还可以添加min,max,默认值等其他约束。如果提交的模型不满足这些约束,将不能保存成功。相当于Asp.net MVC中的DataAnnotations的作用。后面的form验证就基于此。

2.添加路由

 我们需要增加4个路由规则,2个用于添加(一个get,一个post),一个用于删除,一个用于上传图片:

router.get('/book/create', homeController.bookcreateview);
router.post('/book/create', homeController.doBookCreate);
router.delete('/book/:id', homeController.delete);
router.post('/uploadImg', homeController.uploadImg);

基于Express的路由,我们可以创建Restful的路由规则。路由位于app_server文件夹下。

3.添加控制器方法

home.bookcreateview:

module.exports.bookcreateview = function (req, res) {
    res.render('bookCreate', { title: '新增推荐图书' });
};

这里直接是一个get请求,所以直接用render去渲染视图,当然这个bookCreate视图接下来会创建。

doBookCreate:

module.exports.doBookCreate = function (req, res) {    var requestOptions, path, postdata;
    path = "/api/book";
    postdata = {
        title: req.body.title,
        info: req.body.info,
        ISBN: req.body.ISBN,
        brief: req.body.brief,
        tags: req.body.tags,
        img: req.body.img,
        rating:req.body.rating,
    };
    requestOptions = {
        url: apiOptions.server + path,
        method: "POST",
        json: postdata,
    };
    request(requestOptions, function (err, response, body) {
        console.log("body.name", body.name, response.statusCode);        if (response.statusCode === 201) {
            res.redirect("/detail/"+body._id);
        } 
        else if (response.statusCode == 400 && body.name && body.name == "ValidationError") {
            res.render('bookCreate', { title: '新增推荐图书', error:"val"});
        }        else {
            console.log("body.name",body.name);
            info(res, response.statusCode);
        }
    });
};

info:

function info (res, status) {    var title, content;    if (status === 404) {
        title = "404, 页面没有找到";
        content = "亲,页面飞走了...";
    } else if (status === 500) {
        title = "500, 内部错误";
        content = "尴尬...,发生错误";
    } else {
        title = status + ", 有什么不对劲";
        content = "某些地方可能有些错误";
    }
    res.status(status);
    res.render('info', {
        title : title,
        content : content,
        status: status,
    });
};

View Code

在上一节,我们创建了数据操作的api部分。代码的流程就是先从req中获取到前端传过来的数据,然后用request模块调用api,如果添加成功(状态码是201)就返回到detail页面,如果验证失败,就原路返回,并给出提示。如果错误,交给info方法去处理。

delete:

module.exports.delete = function (req, res) {    var requestOptions, path;
    path = "/api/book/" + req.params.id;
    requestOptions = {
        url: apiOptions.server + path,
        method: "delete",
        json: {},
    };
    request(requestOptions, function (err, response, body) {        if (response.statusCode == 204) {
            res.json(1);
        } 
        else {
            res.json(0);
        }
    });
};

如果删除成功,返回的状态码是204,然后返回json(1)让前端去处理界面。

4.添加视图

1) 先需要在图书列表的右侧边栏增加一个按钮:

在books视图中修改:

   .col-md-3
     .userinfo
       p stoneniqiu
       a(href='/book/create').btn.btn-info 新增推荐

当用户点击会跳转到/book/create页面

2)新增推荐页面:

extends layout
include _includes/rating
block content
  .row
   .col-md-12.page.bookdetail
      h3 新增推荐书籍  
      .row
        .col-xs-12.col-md-6
         form.form-horizontal(action='',method="post",role="form")          - if (error == "val")
           .alert.alert-danger(role="alert") All fields required, please try again
          .form-group
            label.control-label(for='title') 书名
            input#name.form-control(name='title')
          .form-group
            label.control-label(for='info') 信息
            input#name.form-control(name='info')            
          .form-group
            label.control-label(for='ISBN') ISBN
            input#name.form-control(name='ISBN')
          .form-group
            label.control-label(for='brief') 简介
            input#name.form-control(name='brief')
          .form-group
            label.control-label(for='tags') 标签
            input#name.form-control(name='tags')
          .form-group
            label.control-label(for='rating') 推荐指数
            select#rating.form-control.input-sm(name="rating")
              option 5
              option 4
              option 3
              option 2
              option 1
          .form-group
            p 上传图片
            a.btn.btn-info(id="upload", name="upload") 上传图片
            br
            img(id='img')
          .form-group
            button.btn.btn-primary(type='submit') 提交

if语句的地方是用来显示错误提示;图片上传,稍后完整介绍;所以提交页面基本长成这样:

3)Mongoose验证

这个时候没有加前端验证,form可以直接提交。但是node打印出了错误日志,Book validation failed,验证失败。

这是Mongoose给我们返回的验证信息,这时界面上回显示一个提示信息:

这是因为在controller中的处理:

  else if (response.statusCode == 400 && body.name && body.name == "ValidationError") {
            res.render('bookCreate', { title: '新增推荐图书', error:"val"});
        }

以上说明了Mongoose会在数据保存的时候验证实体,如果实体不满足path规则,将不能保存。但至此有三个问题,第一个问题是提示信息不明确,当然我们可以遍历输出ValidatorError;第二个就是,验证错误之后,页面原来的数据没有了,需要再输入一遍,这个我们可以参考Asp.net MVC将模型数据填充到视图中可以解决;第三个问题就是页面前端还没有验证,form直接就可以提交了,这个可以通过简单的Jquery脚本就可以做到;这三点先不细究。继续往下看,如果规范输入,这个时候是可以提交的,提交之后在books页面可以看到:

 

4)删除

在标题的右侧增加了一个删除符号(books视图中):

         .col-md-10
            p
             a(href="/Detail/#{book._id}")=book.title             span.close(data-id='#{book._id}') ×

并添加脚本:

$(".close").click(function() {    if (confirm("确定删除?")) {        var id = $(this).data("id");        var row = $(this).parents(".booklist");
        $.ajax({
            url: "/book/" + id,            method: "delete",
        }).done(function(data) {
            console.log(data);
            row.fadeOut();
        });
    }
});

脚本可以先位于layout视图下方:

  script(src='/javascripts/books.js')

这样,删除完成之后会隐藏当前行。下面解决图片上传问题。

二、图片上传

前面我们在路由里面定义了一个uploadimg方法,现在实现它。一般都涉及两个部分,一个是前台图片的提交,一个是后端数据的处理。

1.uploadimg 方法实现

先需要安装formidable模块。

然后在Public文件下创建一个upload/temp文件夹

脚本:

var fs = require('fs');var formidable = require('formidable');
module.exports.uploadImg = function (req, res) {  var form = new formidable.IncomingForm();   //创建上传表单
      form.encoding = 'utf-8';        //设置编辑
      form.uploadDir = './../public/upload/temp/';     //设置上传目录
      form.keepExtensions = true;     //保留后缀
      form.maxFieldsSize = 3 * 1024 * 1024;   //文件大小
    form.parse(req, function(err, fields, files) {
        console.log(files);        if (err) {
            console.log(err);          return res.json(0);        
        }        for (var key in files) {
            console.log(files[key].path);            var extName = ''; //后缀名
            switch (key.type) {            case 'image/pjpeg':
                extName = 'jpg';                break;            case 'image/jpeg':
                extName = 'jpg';                break;            case 'image/png':            case 'image/x-png':            default:
                extName = 'png';                break;
            }            var avatarName = (new Date()).getTime() + '.' + extName;            var newPath = form.uploadDir + avatarName;            
            fs.renameSync(files[key].path, newPath); //重命名
            return res.json("/upload/temp/"+ avatarName);
        }
    });
 
};

这个form会自动将文件保存到upLoadDir目录,并以upload_xxxx格式重新命名,所以最后使用fs模块对文件进行重命名。然后返回给前端。

2.前端

我喜欢用插件,前端我用的是plupload-2.1.8,拥有多种上传方式,比较方便。放置在Public文件下。在layout.jade中引用js:

   script(src='/plupload-2.1.8/js/plupload.full.min.js')
   script(src='/javascripts/books.js')

而在bookCreate.jade视图中,修改如下:

            a.btn.btn-info(id="upload", name="upload") 上传图片
            br            img(id='img')
            input#imgvalue(type='hidden',name='img',value='')

a标签用来触发上传,img用来预览,input用来存放路径。在books.js下增加以下代码:

var uploader = new plupload.Uploader({
    runtimes: 'html5,flash,silverlight,html4',    browse_button: "upload",    url: '/uploadImg',
    flash_swf_url: '/plupload-2.1.8/js/Moxie.swf',
    silverlight_xap_url: '/plupload-2.1.8/js/Moxie.xap',
    filters: {
        max_file_size: "3mb",
                mime_types: [
                    { title: "Image files", extensions: "jpg,gif,png" },
                    { title: "Zip files", extensions: "zip" }
                ]
    },
    init: {
        PostInit: function () {
        },
        FilesAdded: function (up, files) {
            plupload.each(files, function (file) {
                uploader.start();
            });
        },
        UploadProgress: function (up, file) {
        },
        Error: function (up, err) {
        }
    }
});
uploader.init();
uploader.bind('FileUploaded', function (upldr, file, object) {    var data = JSON.parse(object.response);
    console.log(data);    $("#img").attr("src", data);
    $("#imgvalue").val(data);});

提交:

 上传成功后跳转到detail页面。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

互连在线双语商务版
互连在线双语商务版

全自动化、全智能的在线方式管理、维护、更新的网站管理系统主要功能如下:一、系统管理:管理员管理,可以新增管理员及修改管理员密码;数据库备份,为保证您的数据安全本系统采用了数据库备份功能;上传文件管理,管理你增加产品时上传的图片及其他文件。二、企业信息:可设置修改企业的各类信息及介绍。 三、产品管理:产品类别新增修改管理,产品添加修改以及产品的审核。四、订单管理:查看订单的详细信息及订单处理。 五、

下载

JavaScript的事件管理

jQuery、Angular、node中的Promise详解

JS里特别好用的轻量级日期插件

JavaScript关于IE8兼容问题的处理

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

61

2026.02.06

java多线程方法汇总
java多线程方法汇总

本专题整合了java多线程面试题、实现函数、执行并发相关内容,阅读专题下面的文章了解更多详细内容。

28

2026.02.06

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

446

2026.02.06

快手网页版入口与电脑端使用指南 快手官方短视频观看入口
快手网页版入口与电脑端使用指南 快手官方短视频观看入口

本专题汇总了快手网页版的最新入口地址和电脑版使用方法,详细提供快手官网直接访问链接、网页端操作教程,以及如何无需下载安装直接观看短视频的方式,帮助用户轻松浏览和观看快手短视频内容。

258

2026.02.06

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

18

2026.02.06

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

9

2026.02.06

JavaScript 异步编程与事件驱动架构
JavaScript 异步编程与事件驱动架构

本专题深入讲解 JavaScript 异步编程与事件驱动架构,涵盖 Promise、async/await、事件循环机制、回调函数、任务队列与微任务队列、以及如何设计高效的异步应用架构。通过多个实际示例,帮助开发者掌握 如何处理复杂异步操作,并利用事件驱动设计模式构建高效、响应式应用。

12

2026.02.06

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

67

2026.02.05

java中fail含义
java中fail含义

本专题整合了java中fail的含义、作用相关内容,阅读专题下面的文章了解更多详细内容。

30

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.8万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.8万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号