Nodejs_express的使用
准备
安装node,npm 是nodejs package manage,包管理器。主要用于安装依赖包,执行一些命令。
如果安装很慢,修改Npm下载包的路径 :
从taobao下载,执行以下命令;
npm config set registry https://registry.npm.taobao.org
如果要想运行别人的代码,就在当前package.json文件位置,打开命令提示行。输入npm install,自行安装所有依赖包。
node -v,查看node版本号
npm -v,查看Npm的版本号。
npm init -y 初始化项目,生成项目的配置文件package.json 安装 express框架
npm install express --save 或 npm i express --save
创建app.js文件,使用node app.js启动服务器。
了解
common.js (同步的模块加载) , require.js库(AMD异步的模块加载);参考文件,中间件模块,http状态码
100-102 消息
200-207 成功: 200,
300-307 重定向 302,304,
400-449 请求错误 400,404,415 ,
500-600 服务器错误 500
请求头的类型content-type:
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml: XML数据格式
application/atom+xml :Atom XML聚合格式
√ application/json: JSON数据格式
application/pdf:pdf格式
application/msword : Word文档格式
√ application/octet-stream : 二进制流数据(如常见的文件下载)
√ application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
√ multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
npm i morgan --save 安装日志模块
访问服务器的方法:
-- 本机访问:
127.0.0.1:8000
localhost:8000
-- 内网IP:
172.16.2.56:8000
npm i serve-favicon -D (--save-dev) 生成项目依赖 网站小图标
npm i serve-favicon --save (生成项目依赖) 网站小图标
npm uninstall 中间件名称 卸载中间件
app.js
基础配置
// 1.直接引用 express 模块;
const express = require("express");
// 2.创建一个应用程序服务器;web服务器;
const app = express();
// 3.调用set(); 设置Port
// 0-1024范围,是操作系统预留给各种系统应用程序的端口,1024以后的,是其它软件厂商的程序的端口。
app.set("port", 8000)
// __dirname,就是当指向当前项目环境的工作空间目录,即root
// express.static(),设置服务器中,网站静态资源的路径 。(html,css,js,图片等资源)
// app.use():表示配置、设置、使用某一个中间件。
// 中间件:表示可以实现某一个问题的模块。
app.use(express.static(__dirname + '/public'))
// 4.调用监听方法:listen();
app.listen(app.get('port'), ()=>{
console.log("你人生第架服务器,正在运行中..");
})
加入router和中间件
const express = require("express");
const morgan = require("morgan");
const serveFavicon = require("serve-favicon");
const userRouter = require("./route/userRouter") //引用用户功能模块,一定要回加"./",不然找到模块!!
const bodyParser = require("body-parser"); // 处理POST,PUT,DELETE,OPTION请求的中间件,除GET以外的请求
const app = express();//创建一个application服务器;
app.use(morgan("dev")); // 配置日志系统
app.use(serveFavicon(__dirname+"/public/favicon.ico")); //设置网站的小图标
// 在路由配置之前,配置bodyParser
app.use(bodyParser.urlencoded({extended:false})); //处理请求头为 application/x-www-form-urlencoded时;如表单默认的请求头;
app.use(bodyParser.json()); //处理请求头为 application/json时;如AJAX请求时,参数是一个对象时;
/*
extended选项允许您在使用querystring库(when false)或使用qs库(when true)解析URL编码的数据之间进行选择。
querystring只能转换一层JSON对象的格式 ;{a:1,b:2}
qs可以转换多层JSON对象的格式 :{a:1,b:2,c:{x,y,z:{w,h}}}
qs需要单独安装
*/
// 在设置静态资源目录之前,配置路由:
app.use("/", userRouter); //以“/”开头的请求,都先去userRouter进行拦截处理;
app.use(express.static(__dirname+"/public")); //设置静态资源目录
app.set('port',8000) //设置访问的端口
// app.get("port") // 获取指定的属性的值;
// 监听服务器提供服务的端口;
app.listen(app.get("port"), ()=>{
console.log("服务器正常运行中, http://127.0.0.1:8000 ")
})
router和mysql
npm i mysql --save //安装mysql
配置mysql,连接mysql服务器,执行mysql命令,关闭mysql连接;
//处理POST请求方式,需要安装 body-parser中间件;
npm i body-parser --save
----------------------------------------------------------------------
const express = require('express')
const router = express.Router() // 调用Router(),返回一个空的路由对象回来。
const mysql = require('mysql')
//公开路由对象;
module.exports = router;
// router.route("/login")
// .get((req,res)=>{
// let user = req.query
// console.log("get user",user)
// })
// .post(function(req,res){
// let user = req.body
// console.log("post user",user)
// })
router.get("/login", function (req, res) {
let user = req.query;
console.log(user)
if(user.name.length != 0 && user.pass.length != 0){
let con = mysql.createConnection({
host:'localhost',
user:'root',
password:'*******',
port:3306,
database:'w240'
})
// 打开数据库的连接;连接到数据库;
con.connect()
let sql = "SELECT * FROM users WHERE user = ? AND pass = ?"
// mysqlConnection.query(sql,param,callback);
// 'insert into n_user value(null,?,?);'在mysql语句中,凡是变量的地方,用?来替换,防止 SQL注入漏洞产生。
// ??和param变量的数量是一一对应;
con.query(sql,[user.name,user.pass],function(error,data){
console.log("error-------",error); //error------- null
console.log("data-------",data); //data------- []
if(data.length === 1){
// console.log("error:",error);
//操作MYSQL失败时,error不为Null. 成功是为null;
// console.log("data:",data);
// 操作MYSQL失败时,data是undefined
// 成功时,是一个object对象,如果是select语句,就是一个数组对象;
res.redirect('pages/main.html')
}else{
res.redirect('index.html')
}
})
con.end()
}
})
//post请求时,获取请求的参数,通过request.body来获取
router.post('/register',function(req,res){
let user = req.body //body中的属性名,来自于form中,input等的name标签属性的值;
if(user.name.length != 0 && user.pass.length != 0){
let con = mysql.createConnection({
host:'localhost',
user:'root',
password:'**********',
port:3306,
database:'w240'
})
con.connect()
let sql = " insert into users value(null,?,?)"
con.query(sql,[user.name,user.pass],function(error,data){
console.log("error-------",error); //error------- null
console.log("data-------",data); //data------- []
if (error == null) {
// res.send("注册成功")
res.redirect("pages/main.html") //重定向到另个页面,访问成功注册的页面。
} else {
// res.send("注册失败")
res.redirect("index.html") //注册失败,重写向到失败页面
}
})
con.end()
}
})
Form表单提交请求
//html GET、POST
<form action="/login" method="GET">
<label for="">
用户名:
<input type="text" name="name" id="">
</label>
<label for="">
密码:
<input type="password" name="pass" id="">
</label>
<button type="submit">提交</button>
</form>
<form action="/register" method="POST">
<label for="">
用户名:
<input type="text" name="name" id="">
</label>
<label for="">
密码:
<input type="password" name="pass" id="">
</label>
<button type="submit">提交</button>
</form>
ajax的使用
//html
<label for="">
user:
<input type="tel" name="name" id="n1">
</label>
<label for="">
pass:
<input type="password" name="pass" id="p1">
</label>
<button type="button" id="login">登录</button>
<hr>
<label for="">
user:
<input type="tel" name="name" id="n2">
</label>
<label for="">
pass:
<input type="password" name="pass" id="p2">
</label>
---------------------------------------------------------------------------------------------
//js
let loginbtn = document.getElementById('login')
let registerbtn = document.getElementById('register')
loginbtn.onclick = () =>{
localStorage.removeItem('user')
let name = $('#n1').val()
let pass = $('#p1').val()
let user = {
name,
pass
}
console.log(user)
$.ajax({
type:'GET',
url:'/login',
data:user,
success:function(res){
console.log(res)
if(res.state == 1){
localStorage.setItem('user',JSON.stringify(res.name))
alert('登陆成功')
window.location.href = './page/main.html'
}
}
})
}
registerbtn.onclick = () =>{
let name = $('#n2').val()
let pass = $('#p2').val()
let user = {
name,
pass
}
// $.ajax({
// type:'POST',
// url:'/register',
// data:user,
// success:function(res){
// console.log(res)
// if(res.state == 1){
// alert(`${res.msg}`)
// }
// }
// })
//原始ajax
let xhr;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
xhr.open('post','/register',true)
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xhr.send(`name=${name}&pass=${pass}`)
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
let res = JSON.parse(xhr.responseText)
console.log(res)
if(res.state == 1){
alert(`${res.msg}`)
}
}
}
}
配合nodejs的router配置:
const express = require('express')
const mysql = require('mysql')
const router = express.Router()
module.exports = router
router.route('/login').get((req,res)=>{
console.log(req.query)
let user = req.query
console.log("get------->",user);
if(user.name.length!=0 && user.pass.length!=0){
let con = mysql.createConnection({
host:'localhost',
user:'root',
password:'**************',
database:'w240'
})
con.connect()
let sql = 'SELECT user,pass FROM users WHERE user = ? AND pass = ?'
con.query(sql,[user.name,user.pass],function(error,data){
console.log("err",error);
console.log("data",data);
if(data.length == 1){
// res.redirect('page/main.html')
return res.json({
name:user.name,
msg:'登录成功',
state:1
})
}else{
res.redirect('index.html')
}
})
con.end()
}
})
router.route('/register').post((req,res)=>{
let user = req.body
console.log("post------->",user);
if(user.name.length!=0 && user.pass.length!=0){
let con = mysql.createConnection({
host:'localhost',
user:'root',
password:'***********,
database:'w240'
})
con.connect()
let sql = 'INSERT users VALUES(null,?,?)'
con.query(sql,[user.name,user.pass],function(error,data){
console.log("err",error);
console.log("data",data);
if(error == null){
res.json({
msg:'注册成功!请登录',
state:1
})
}else{
res.redirect('index.html')
}
})
con.end()
}
})
原生ajax
- 概念:
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。
创建AJAX的 XMLHttpRequest对象
let xhr;
if (window.XMLHttpRequest) {
// 非IE浏览器的支持写法;
xhr = new XMLHttpRequest();
} else {
// IE5/6 支持的写法:
xhr = new ActiveXObject(“Microsoft.XMLHTTP”)
}
向服务器发送请求
如需将请求发送到服务器,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:
xhr.open(method,url,async);
method:请求的类型;GET 或 POST
url:文件在服务器上的位置
async:true(异步)或 false(同步)
xhr.send(string);
string:仅用于 POST 请求
setRequestHeader():当是POST请求时,必须设置请求头信息,不然后端无法获取参数的数据!!!
xhr.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
get请求时:
xhr.open(‘get’,“url?key=value&key=value”,true)
xhr.send()
监听XMLHttpRequest 的状态:
xhr.onreadystatechange = function(){
当readyState === 4 ,status === 200
时,才会更新DOM。
}
readyState 属性的值:
存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
0: 请求未初始化
1: 服务器连接已建立
2: 请求已接收
3: 请求处理中
4: 请求已完成,且响应已就绪
status属性:200: “OK”,404: 未找到页面
responseText 获得字符串形式的响应数据。
responseXML 获得 XML 形式的响应数据。
AJAX实现的7个步骤:
1 创建AJAX XMLHttpRequest对象;
2. open(method, url,true);打开一个请求的链接(POST请求,添加请求头。)
setRequestHeader()
3. send(string || null);发起请求
4. 监听状态的变化
5. 判断状态的变化,并处理响应回来结果;
6. 写NODEJS后台的逻辑;
7. 回到前端页面中,更新页面的DOM数据或者页面的跳转等业务。
get请求数据
xmlhttp.open(“GET”,"/try/ajax/demo_get2.php?fname=Henry&lname=Ford",true);
xmlhttp.send();
post请求数据
xmlhttp.open(“POST”,"/try/ajax/demo_post2.php",true);
xmlhttp.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded”);
xmlhttp.send(“fname=Henry&lname=Ford”);
案例:
let xhr
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest()
}else{
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
xhr.open('get','/getlist',true)
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState ==4 && xhr.status == 200){
let res = JSON.parse(xhr.responseText)
console.log(res);
}
}
封装mysql配置
新建mysql配置文件:
const mysql = require('mysql')
module.exports = {
config:{
host:'localhost',
user:'root',
password:'*************',
port:3306,
database:'w240'
},
query(sql,param,cb){
let con = mysql.createConnection(this.config)
con.connect()
con.query(sql,param,cb)
con.end()
}
}
以登录为案例:在user.js引入mysql,直接使用mySql.query调用方法query。
const mySql = require('./mysql')
router.route('/login').get((req,res)=>{
console.log(req.query)
let user = req.query
console.log("get------->",user);
if(user.name.length!=0 && user.pass.length!=0){
let sql = 'SELECT user,pass FROM users WHERE user = ? AND pass = ?'
let param = [user.name,user.pass]
let cb = function(error,data){
console.log("err",error);
console.log("data",data);
if(data.length == 1){
return res.json({
name:user.name,
msg:'登录成功',
state:1
})
}else{
res.redirect('index.html')
}
}
mySql.query(sql,param,cb)
}
})
封装抛出的mysql为一个promise对象
const mysql = require('mysql')
module.exports = {
config:{
host:'localhost',
user:'root',
password:'Forgive22',
database:'mirror',
port:3306
},
query(sql,param){
return new Promise((resolve, reject) => {
let con = mysql.createConnection(this.config);
con.connect();
con.query(sql, param, (err, data) => {
if (err) { // fail=>{}
reject(err)
} else { // ok => null
resolve(data) //返回数据库查询的结果
}
});
con.end();
});
}
}
以动态渲染主导航和子导航为例使用mysql:
const express = require('express')
const mysql = require('./mysql')
const router = express.Router()
router.route('/getMenus')
.get((req,res)=>{
let sql = "select * from m_menu";
let menus = [];
let summenus = []
mysql.query(sql,[])
.then((success)=>{
menus = success
let sql = "select * from m_submenu";
return mysql.query(sql,[])
})
.then((success)=>{
summenus = success
res.json({
status:200,
msg:"成功",
data:[menus,summenus]
})
})
.catch((errorResult) => {
console.log(errorResult);
res.json({
status: 40001,
msg: "获取菜单数据失败",
data: []
})
});
})
module.exports = router
Nodejs实现CORS跨域
使用的标准是CORS,即跨域资源共享。CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了只能同源使用的限制。
app.js配置:
// CORS配置跨域请求:
app.use('/*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
next();
})
当session遇上跨域
在一个跨域请求的项目中,需要存储提个session为后续的操作做一个判断依据:
结果获取到的都是null,查阅了相关资料,才了解到这是因为当进行跨域时,每一次请求都没有将sessinId带过去,服务器就认为是一个没有登录的新请求,都会在cookie里set一个新的sessionId,所以我之前存的值永远也取不到。
Session:在计算机中,尤其是在网络应用中,称为“会话控制”。Session 对象存储特定用户会话所需的属性及配置信息。即服务端用于区分特定用户的数据结构。一般的做法都是在客户端通过验证后,服务端将一个sessionId告诉客户端,在随后的通讯中,客户端将sessionId告诉服务端,用Cookie携带SessionID,服务器根据SessionID管理该用户会话、权限,服务端通过验证sessionId的方法来确认客户端的身份。这里面的核心就是session是在服务端管理的,将id交给客户端用作区分。
因此在跨域时,需要在各个环节上都要保证客户端的sessionid不能丢失,否则就会被服务端拦截,无法获取服务的问题。
解决方案:
ajax请求设置为如下:
$.ajax({
url: commonUrl + url,
type: 'post',
data: JSON.stringify(obj),
//加上 xhrFields及crossDomain
xhrFields: {
withCredentials: true//允许带上凭据
},
crossDomain: true,
//
success:function(res){
},
error:function(){
}
});
后台都统一添加:
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));//处理跨域
response.setHeader("Access-Control-Allow-Credentials", "true");//表示是否允许发送Cookie
在一开始解决跨域时,我采用的是 response.setHeader(“Access-Control-Allow-Origin”, “*”) 处理跨域,表示接受任意域名的请求。
但是设置了response.setHeader(“Access-Control-Allow-Credentials”, “true”)后,就不能使用“*”。
不过要处理好跨域,可以直接设置允许请求的域名:response.setHeader(“Access-Control-Allow-Origin”, “域名名称”)。
session存储并设置cookie
安装express-session
npm i express-session --save
配置session
const expressSession = require("express-session");
app.use(expressSession({ //使用该配置后,req.session就会返回一对象; req对象中,添加了session对象。
secret:"abc",
name: "userState",
resave: false,
saveUninitialized: true,
cookie: {
maxAge:1000*60*60
},
rolling:false //建议设置为false,以验证session失效。
}))
解析每一项的作用:
//配置中间件
app.use(session({
secret: 'this is string key', // 可以随便写。 一个 String 类型的字符串,作为服务器端生成 session 的签名
name:'session_id',/*保存在本地cookie的一个名字 默认connect.sid 可以不设置*/
resave: false, /*强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。*/
saveUninitialized: true, //强制将未初始化的 session 存储。 默认值是true 建议设置成true
//设置cookie在浏览器端
cookie: {
maxAge:1000*60 /*过期时间1min*/
}, /*secure https这样的情况才可以访问cookie*/
//设置过期时间比如是30分钟,只要游览页面,30分钟没有操作的话在过期
rolling:true //在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)
}))
设置404页面
// 处理404问题
app.all("*",function(req,res){
// res.send('404页面')
// 发送一个文件的内容给客户端
res.sendFile(__dirname+"/public/404.html")
})
使用模板html
ejs和ajax跳转详情页
ajax
在a标签中先控制路由跳转,并动态传入当前点击的id:
然后在detail页面截取到location.href里面的id,ajax发起请求:
后台查询返回对应的数据,前端再由res渲染页面:
ejs
安装ejs
npm i ejs --save
创建views存放模板html
app.js中引入并配置:
const ejs = require('ejs')
//ejs的使用:
//设置模板视图的目录
app.set("views",__dirname + "/views"); //设置模板html为访问views文件夹
//设置是否启用视图编译缓存,启用将加快服务器执行效率
app.set("view cache",true);
// 2.注册html模板引擎:
app.engine('html',ejs.__express);
//设置模板引擎的格式即运用何种模板引擎
app.set("view engine","html");
设置动态路由goodsRouter.js:
使用req.params获取传入的id
给模板页面传数据:res.render(“views文件夹下的模板html名如:xxx.html”,{数据名1:数据值1,数据名2:数据值2})
const express = require("express")
const router = express.Router();
const db = require("./mysql")
module.exports = router;
// 动态路由 /goods/list/11, 利用路由中的URL传递参数:
router.route("/list/:gid")
.get((req, res) => {
// 获取动态路由中的参数
console.log(req.params); //{ gid: '44' }
let gid = req.params.gid;
let sql = "select * from m_goods g,m_style s where g.goods_style_id = s.style_id AND style_id= ?;"
let param = [gid]
db.query(sql, param)
.then((data) => {
console.log(data);
res.render("city-man.html", {
bannerImg: "/img/" + data[0].style_banurl,
cnName: data[0].style_name,
enName: data[0].style_enName,
goods: data // 对应一个数组
}
);
})
.catch((err) => {
res.json({
status: 40001,
msg: '查询数据失败',
data: []
})
});
})
在app.js引入goodsRouter.js并使用:
const goodsRouter = require("./routes/goodsRouter")
app.use('/goods',goodsRouter) //路由拦截
将模板页面数据改为模板数据:
页面中使用以下显示模板数据
- 直接显示模板数据<%= 模板变量名 %>
- 循环展示:
<% for(let i = 0 ; i < 模板变量名.length; i++){ %>
<%= 模板变量名[i].xxx %>
<% }%>
案例:
views文件夹下的city-man.html
直接使用模板变量:
<img class="img-fluid" src="<%= bannerImg %>" alt="">
循环显示:
<div class="row justify-content-start">
<% for(let i = 0 ; i < goods.length; i++){ %>
<div class="col-3 mt-3 product-list-item">
<div class="product-number"><%= goods[i].goods_num %></div>
<div><img class="product-img" src="/img/<%= goods[i].goods_slt %> " alt=""></div>
<div class="product-link">
<a href="/goodsdetails/<%= goods[i].goods_id %>" class="text-dark product-link-size">
了解产品详情
<br>
<i class="fa fa-arrow-circle-o-right"></i>
</a>
</div>
</div>
<% }%>
</div>
ejs模板+data数据=静态页面
ajax和ejs对比
文件上传
依赖于multer模块,router.js中处理:
const multer = require(“multer”) //1.引用文件中间件
const upload = multer({ dest: ‘uploads/’ });
//2. 会自动 基于项目根目录 (nodeJs)来创建uploads目录;
const fs = require(“fs”); //引用NODEjs自带的文件系统模块;
普通表单上传
html
<form name="userInfo1" action="/modifyUserInfo" method="POST" enctype="multipart/form-data">
<div class="form-group row">
<label for="usernick" class="col-lg-2 text-right col-form-label col-form-label-sm">昵称</label>
<div class="col-lg-8">
<input type="text" class="form-control " placeholder="用户昵称" value="张三" id="usernick" name="userName">
</div>
</div>
<div class="form-group row">
<label for="userPhoto" class="col-md-2 text-right col-form-label">用户头像</label>
<div class="col-md-8">
<input type="file" class="form-control" placeholder="请选择一个本地文件" id="userPhoto" name="userPhoto">
</div>
</div>
<div class="form-group row">
<label for="userbirthday" class="col-md-2 text-right col-form-label">出生日期</label>
<div class="col-lg-8">
<input type="datetime-local" name="birthday" class="form-control" id="userbirthday">
</div>
</div>
<div class="form-group row">
<div class="col-lg-2 text-right">性别</div>
<div class="col-lg-8">
<div class="form-check">
<input class="form-check-input" type="radio" name="sex" id="sex1" value="男" checked>
<label class="form-check-label" for="sex1">
男
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="sex" id="sex2" value="女" checked>
<label class="form-check-label" for="sex2">
女
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="usertel" class="col-md-2 text-right col-form-label">电话</label>
<div class="col-lg-8">
<input type="tel" name="tel" class="form-control" id="usertel">
</div>
</div>
<div class="form-group row">
<label for="usermail" class="col-md-2 text-right col-form-label">电子邮箱</label>
<div class="col-lg-8">
<input type="email" name="email" class="form-control" id="usermail">
</div>
</div>
<div class="form-group row">
<div class="col-lg-4 offset-2 text-right">
<button type="submit" class="btn btn-dark">提交</button>
</div>
<div class="col-lg-4">
<button type="reset" class="btn btn-secondary">重置</button>
</div>
</div>
</form>
router.js
// 修改用户资料,
router.route("/modifyUserInfo")
// single("参数名"),<input type= "file" name = "参数名" />
.post(upload.single('userPhoto'), (req, res) => {
// req.file=>接受上传的文件对象;
// req.body => 其它表单域提交的数据;
console.log(req.file)
console.log(req.body);
if (req.file != undefined) {
let fileLastName = req.file.originalname.split(".")[1]; //获取原文件的扩展名 (.jpg)
let oldFile = "uploads/"+req.file.filename;
// let newFile = req.file.filename +"."+ fileLastName
let newFile = 'public/fileUploads/' + new Date().getTime() + "." + fileLastName;
fs.rename(oldFile, newFile, (err) => {
if (err) {
throw err;
} else {
// 组成新的文件路径 ,存储于Mysql中;
let pathName = newFile.replace("public/",'');
let { userName, birthday, sex, tel, email } = req.body;
// let u_id = req.session.user.id;
let u_id = 17;
let sql = `insert into m_userinfo value(?,?,?,?,?,?,?)`;
let param = [u_id,userName,tel,birthday,email,sex,pathName]
db.query(sql, param)
.then(data=>{
res.redirect("/html/myorder.html#userinfo")
})
.catch(err=>{
throw new Error("插入或修改失败")
})
}
})
}
})
ajax文件上传
htnl
<form name="userInfo2" >
<div class="form-group row">
<label for="usernick" class="col-lg-2 text-right col-form-label col-form-label-sm">昵称</label>
<div class="col-lg-8">
<input type="text" class="form-control " placeholder="用户昵称" value="张三" id="usernick" name="userName">
</div>
</div>
<div class="form-group row">
<label for="userPhoto" class="col-md-2 text-right col-form-label">用户头像</label>
<div class="col-md-8">
<input multiple type="file" class="form-control" placeholder="请选择一个本地文件" id="userPhoto" name="userPhoto">
</div>
</div>
<div class="form-group row">
<label for="userbirthday" class="col-md-2 text-right col-form-label">出生日期</label>
<div class="col-lg-8">
<input type="datetime-local" name="birthday" class="form-control" id="userbirthday">
</div>
</div>
<div class="form-group row">
<div class="col-lg-2 text-right">性别</div>
<div class="col-lg-8">
<div class="form-check">
<input class="form-check-input" type="radio" name="sex" id="sex1" value="男" checked>
<label class="form-check-label" for="sex1">
男
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="sex" id="sex2" value="女" checked>
<label class="form-check-label" for="sex2">
女
</label>
</div>
</div>
</div>
<div class="form-group row">
<label for="usertel" class="col-md-2 text-right col-form-label">电话</label>
<div class="col-lg-8">
<input type="tel" name="tel" class="form-control" id="usertel">
</div>
</div>
<div class="form-group row">
<label for="usermail" class="col-md-2 text-right col-form-label">电子邮箱</label>
<div class="col-lg-8">
<input type="email" name="email" class="form-control" id="usermail">
</div>
</div>
<div class="form-group row">
<div class="col-lg-4 offset-2 text-right">
<button type="button" class="btn btn-dark" id="modifyUserInfo">提交</button>
</div>
<div class="col-lg-4">
<button type="reset" class="btn btn-secondary">重置</button>
</div>
</div>
</form>
router.js
// 修改用户资料,AJAX方式
router.route("/modifyUserInfoAjax")
// single("参数名"),<input type= "file" name = "参数名" />
.post(upload.single('userPhoto'), (req, res) => {
// req.file=>接受上传的文件对象;
// req.body => 其它表单域提交的数据;
console.log(req.file)
console.log(req.body);
if (req.file != undefined) {
let fileLastName = req.file.originalname.split(".")[1]; //获取原文件的扩展名 (.jpg)
let oldFile = "uploads/"+req.file.filename;
// let newFile = req.file.filename +"."+ fileLastName
let newFile = 'public/fileUploads/' + new Date().getTime() + "." + fileLastName;
fs.rename(oldFile, newFile, (err) => {
if (err) {
throw err;
} else {
// 组成新的文件路径 ,存储于Mysql中;
let pathName = newFile.replace("public/",'');
let { userName, birthday, sex, tel, email } = req.body;
// let u_id = req.session.user.id;
let u_id = 17;
let sql = `insert into m_userinfo value(?,?,?,?,?,?,?)`;
let param = [u_id,userName,tel,birthday,email,sex,pathName]
db.query(sql, param)
.then(data=>{
res.json({
status:200,
msg:"修改用户信息成功",
data:param
})
})
.catch(err=>{
res.json({
status:40001,
msg:"修改用户信息失败",
data:[]
})
})
}
})
}
})
AJAX请求,上传文件时,后端接口编码是multipart/form-data;前端使用 FormData对象来传参数 ;
把form的DOM对象放放new FormData()中,自动把表单域中所有值 ,都添加到new FormData()中。
FormData对象的数据,只能通过get()来获取 ;get()中放入表单域的name的值
console.log(formData); //FormData {},是不可见数据
- 原生的AJAX,formData时,不要请求头;
- $ajax时processData设置为false。因为data值是FormData对象,不需要对数据做处理。contentType设置为false。因为是由表单构造的FormData对象,且已经声明了属性enctype=“multipart/form-data”,所以这里设置为false。
js文件
let modifyUserInfo = document.getElementById("modifyUserInfo");
const modifyUserInfoFn = () => {
// AJAX请求,上传文件时,后端接口编码是multipart/form-data;
// 前端使用 FormData对象来传参数 ;
// 把form的DOM对象放放new FormData()中,自动把表单域中所有值 ,都添加到new FormData()中。
let formData = new FormData(document.getElementsByName("userInfo2")[0])
// console.log(formData); //FormData {},是不可见数据
// FormData对象的数据,只能通过get()来获取 ;get()中放入表单域的name的值
// console.log(formData.get("userName"));
// console.log(formData.get("userPhoto"));
// 1. 原生 的
let xhr = new XMLHttpRequest();
xhr.open("post","/modifyUserInfoAjax", true)
// 原生的AJAX,formData时,不要请求头;
xhr.send(formData)
xhr.onreadystatechange= ()=>{
if(xhr.readyState === 4 && xhr.status === 200){
let response = xhr.responseText;
console.log(response);
}
}
// 2. $.ajax()
$.ajax({
url: "/modifyUserInfoAjax",
type: 'POST',
cache: false, //cache设置为false,上传文件不需要缓存。
data: formData,
processData: false, //processData设置为false。因为data值是FormData对象,不需要对数据做处理。
contentType: false, //contentType设置为false。因为是由<form>表单构造的FormData对象,且已经声明了属性enctype="multipart/form-data",所以这里设置为false。
success: function (result) {
if(result.status === 200){
// 直接根据返回数据中的data,更新dom数据;
// 或者 重新加载 当前页;
location.reload(); //必须要保证页面有请求后台,获取用户信息数据;
}
},
error: function (err) {
console.log(err)
alert(err.msg)
}
});
}
modifyUserInfo.onclick = modifyUserInfoFn;