對(duì)于一個(gè)前端開(kāi)發(fā)人員來(lái)說(shuō)歇式,node.js可以說(shuō)是開(kāi)發(fā)后端的福音每强。本人畢設(shè)項(xiàng)目使用的是asp.net(只是使用ashx來(lái)接收前端的ajax逻住,并沒(méi)有使用那些惡心的控件)创葡,通過(guò)對(duì)比發(fā)現(xiàn)整個(gè)項(xiàng)目都使用js實(shí)在是幸福蛮浑。
Node.js
關(guān)于node.js的優(yōu)點(diǎn)就不再多說(shuō)唠叛,網(wǎng)上一搜一大堆,項(xiàng)目也可以找到很多沮稚。這里主要說(shuō)一下node.js關(guān)于搭建web應(yīng)用這一塊的缺點(diǎn)艺沼。
眾所周知,node.js需要自己搭建服務(wù)器蕴掏,也就是說(shuō)你需要自己監(jiān)聽(tīng)一個(gè)端口并啟動(dòng)它
var http=require('http');
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write("hello sunnychuan");
res.end();
}).listen(3000);
console.log("server is running!");
這里有一本電子書(shū)幫助你使用原生的node.js搭建web應(yīng)用障般,點(diǎn)擊這里
不僅僅是監(jiān)聽(tīng)端口,我們往往會(huì)根據(jù)用戶(hù)輸入的url從本地找到相應(yīng)文件并將它寫(xiě)回請(qǐng)求
fs.exists(filePath,function(exists){
if(exists){
res.writeHead(200,{'Content-Type':contentType});
var stream=fs.createReadStream(filePath);
stream.on('error',function(){
res.writeHead(500,{'Content-Type':'text/html'});
res.end('<h1>500 Server Error</h1>');
});
stream.pipe(res);
}
}
我們還會(huì)針對(duì)前端的ajax請(qǐng)求做路由處理
//根據(jù)不同的路徑調(diào)用不同的處理程序
var handle={};
handle["/api/get.json"]=requestHandlers.get;
handle["/api/post.json"]=requestHandlers.post;
function route(handle,pathname,req,res){
if(typeof handle[pathname]==='function'){
handle[pathname](req,res);
}
else{
res.writeHead(404,{'Content-Type':'text/html'});
res.write('<h1>404 Not Found</h1>');
res.end();
}
}
var pathname=decodeURI(url.parse(req.url).pathname);
if(path.extname(pathname)=='.json'){
route(handle,pathname,req,res);
}
通過(guò)上面那么一折騰盛杰,原本的熱情就消退了一半挽荡,這里我推薦一下express框架,官方文檔在這里
Express
安裝和目錄結(jié)構(gòu)
首先安裝express
npm install express --save-dev
安裝express的應(yīng)用生成器
npm install express-generator -g
使用它的應(yīng)用生成器可以很快建立一個(gè)項(xiàng)目
express myapp
然后進(jìn)入到該文件夾下即供,安裝所有依賴(lài)
cd myapp
npm install
你的目錄結(jié)構(gòu)長(zhǎng)這個(gè)樣子
bin是啟動(dòng)項(xiàng)定拟,在bin/www里面你可以修改端口號(hào)
node_modules用來(lái)存放npm安裝的模塊
public里面用來(lái)存放資源
routes是路由控制,存放了所有的處理程序
views是視圖文件逗嫡,相當(dāng)于html頁(yè)青自,在routes中會(huì)使用類(lèi)似
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
這樣的代碼來(lái)替換模板引擎里的內(nèi)容株依,有點(diǎn)像java的.jsp文件和asp.net的.asp文件
app.js用來(lái)配置express,你可以在這里進(jìn)行路由分配和錯(cuò)誤處理并按需加載中間件
啟動(dòng)項(xiàng)目
npm start
修改代碼
作為前端開(kāi)發(fā)的你延窜,也許會(huì)厭惡由后端直接將數(shù)據(jù)渲染在頁(yè)面上(至少我是這樣)恋腕,我們通常使用ajax來(lái)進(jìn)行前后端交互并自行處理后端的數(shù)據(jù),因此整個(gè)views文件就可以直接delete掉了逆瑞。
step1 更改目錄結(jié)構(gòu)
把public更名為client荠藤,新建server文件夾并把routes和app.js放到里面(views直接刪除即可),這樣一來(lái)整個(gè)項(xiàng)目結(jié)構(gòu)就比較明顯了呆万,客戶(hù)端和服務(wù)端分離商源。
step2 修改routes文件夾
routes里默認(rèn)有index.js和users.js兩個(gè)路由文件,其中index.js是負(fù)責(zé)模板渲染的
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
而users.js是直接返回一個(gè)字符串
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
既然我們刪掉了views谋减,那么index.js的代碼肯定要修改的牡彻。我刪掉了這兩個(gè)文件,并新建了get.js和post.js文件用來(lái)接收和處理前端的ajax請(qǐng)求
//get.js
module.exports=function(req,res){
console.log(req.query.userName);
res.json({code:200,data:"this is a get request"});
}
//post.js
module.exports=function(req,res){
console.log(req.body.userName);
console.log(req.body.password);
res.json({code:200,data:"this is a post request"});
}
另外出爹,我還新建了一個(gè)名為router.js的文件庄吼,用來(lái)分配路由(默認(rèn)是在app.js文件中進(jìn)行路由分配的,但是一旦請(qǐng)求過(guò)多严就,app.js會(huì)十分冗長(zhǎng))
var express=require('express');
var router=express.Router();
var get=require('./get');
var post=require('./post');
router.get('/get.json',get);
router.post('/post.json',post);
module.exports=router;
step3 修改app.js
對(duì)模塊加載做如下修改
//修改前
var index = require('./routes/index');
var users = require('./routes/users');
//修改后
var router=require('./routes/router.js');
刪掉視圖引擎的設(shè)置
//刪除下面的代碼
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
對(duì)靜態(tài)資源的加載做一些更改总寻,默認(rèn)是在"public"文件夾下讀取并加載靜態(tài)資源的,現(xiàn)在我們?cè)O(shè)置為先從根路徑讀取文件梢为,如果不存在則從"client"中讀取文件
//修改前
app.use(express.static(path.join(__dirname, 'public')));
//修改后
var rootDir=path.resolve(__dirname);
var projectDir=path.resolve(__dirname,'../','client');
app.use(express.static(rootDir));
app.use(express.static(projectDir));
替換默認(rèn)的路由加載渐行,改為上面require的router。/api是一個(gè)虛擬路徑铸董,這樣每當(dāng)我們?cè)L問(wèn)/api/xxx.json就會(huì)通過(guò)路由來(lái)分配不同的控制器完成業(yè)務(wù)邏輯
//修改前
app.use('/', index);
app.use('/users', users);
//修改后
app.use('/api',router);
我們還需要讓根路徑加載首頁(yè)面
app.get('/', function(req, res){
res.sendFile(projectDir+'/index.html');
});
由于不需要渲染視圖祟印,因此錯(cuò)誤頁(yè)面的處理也要進(jìn)行修改,我這里僅僅是把錯(cuò)誤信息返回給前端
//修改前
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
//修改后
app.use(function(err, req, res, next) {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.json({code:500,msg:"error"});
});
測(cè)試
我們需要編寫(xiě)前端代碼進(jìn)行測(cè)試粟害,這里我使用angular簡(jiǎn)單地發(fā)送get和post請(qǐng)求
angular.module("indexApp",[])
.controller("IndexCtrl",function($scope,$http){
$scope.get=function(){
$http({
method:"get",
url:"/api/get.json",
params:{userName:"sunnychuan"}
}).then(function(res){
if(res.data.code==200){
console.log(res.data.data);
}
else if(res.data.code==500){
console.log(res.data.msg);
}
})
}
$scope.post=function(){
$http({
method:"post",
url:"/api/post.json",
data:{userName:"sunnychuan",password:"qc"}
}).then(function(res){
if(res.data.code==200){
console.log(res.data.data);
}
else if(res.data.code==500){
console.log(res.data.msg);
}
})
}
})
同樣的蕴忆,使用npm start啟動(dòng)項(xiàng)目,在url中輸入localhost:3000
點(diǎn)擊get按鈕
點(diǎn)擊post按鈕
至此悲幅,基本的環(huán)境搭建成功套鹅,搭配mongodb會(huì)在之后的文章中介紹。