1 URL
URL 包含
协议 主机名 端口 路径 查询字符串 信息片段
http:// localhost :3000 /about ?test=1&name=1 #history
- 端口:默认http端口为80,https端口为443,如果不用这俩的话就需要使用大于1023的端口号
- 信息片段:该片段只在浏览器中使用不会传递给服务器
2 HTTP请求方法
输入URL并访问后,浏览器会对服务器发送GET或POST请求。
3 请求报头和响应报头
发送到服务器的数据并不单单是URL,同时会发送很多隐性的信息,服务器响应请求时也会回传一些隐性的信息给服务器,之前写的ContentType就是表示web数据类型的字段。
post请求最常见的媒体类型为multipart?form-data,ajax请求使用application/json
4 请求对象
通常命名为request或req,声明周期起始于Node中http.IncomingMessage对象,简单介绍下req中包含的属性和方法
- req.params :包含命名过的路由参数
- req.query:包含以键值对存放的查询字符串参数(一般称为get请求参数)
- req.body:包含POST请求参数
- req.route:当前匹配路由信息
- req.cookies/req,singnedCookies 一个对象,包含从客户端传递过来的cookies值
- req.headers 从客户端接收到的请求报头
- req.accepts([types]): 一个方法,用来确定客户端是否接受一个或一组指定的类型
- req.ip 客户端ip地址
- req.path 请求路径
- req.host 一个方法,用来返回客户端报告的主机名
- req.xhr 如果请求是ajax发送的返回true
- req.protocol 用于标识请求协议(http 或 https)
- req.secure 如果链接安全返回true,等同于 req.protocol == ‘https’
- req.url/req.originalUrl 返回路径和查询字符串(不包含协议主机或端口)、url可以重写,req.orginalUrl旨在保留原始请求和查询字符串
- req.acceptedLanguages 返回客户端首选的语言(从请求报头中获得)
5 响应对象
通常命名为res
- res.status(code) 设置http状态码,默认200为成果,可以设置404-页面不存在,500-服务器错误
- res.set(name,value) 设置响应头,通常不需要手动设置
- res.redirect([status],url) 重定向浏览器,默认重定向代码是302,
- res.send(body),res.send(stauts,body): 向客户端发送响应以及可选的状态码,Express默认内容类型为text/html,如果要改,需要在send前调用
res.send(‘Content-Type’,‘text/plain’)。如果body是一个对象或者数组,响应会以JSON发送,不过发送json推荐使用res.json
-
res.json(json) res.json(status,json) 向客户端发送JSON以及可选的状态码
-
res.jsonp(json) res.jsonp(status,json) 向客户端发送JSONP以及可选的状态码
-
res.type(type) 用于设置content-type
-
res.format(object) 可以根据不同请求报头发送不同的内容
-
res.attachment([filename]),res.download(path,[filename],[callback]) 这俩方法会将响应报头Content-Disposition设置为attachment,浏览器会选择下载而不是展现内容。可以执行filename作为浏览器给用户的提示,download可以自定要下载的文件,此外你还要把要下载的内容发到客户端
-
res.sendFile(path,[option],[callback])
根据路径读取文件发到客户端
-
res.links(links) 设置连接响应报头
-
res.locals,res.render(view,[locals],callback) res.locals包含渲染视图的默认上下文,res.render使用配置的模板引擎渲染视图
6 关于express
API文档:http://expressjs.com/api.html
github源码:https://github.com/ visionmedia/express/tree/master
源码中的代码说明
- lib/application.js Express 主接口。如果想了解中间件是如何接入的,或视图是如何被渲染的,可以看 这里。
- lib/express.js 这是一个相对较短的 shell,是 lib/application.js 中 Connect 的功能性扩展,它返回一个 函数,可以用 http.createServer 运行 Express 应用
- lib/request.js 扩展了 Node 的 http.IncomingMessage 对象,提供了一个稳健的请求对象。关于请求对 象属性和方法的所有信息都在这个文件里。
- lib/response.js 扩展了 Node 的 http.ServerReponse 对象,提供响应对象。关于响应对象的所有属性和 方法都在这个文件里。
- lib/router/route.js 提供基础路由支持。尽管路由是应用的核心,但这个文件只有不到 200 行,你会发现它 非常地简单优雅
7 简单示例
7.1 内容渲染
一般内容渲染使用res.render
app.get('/', function (req, res) {
res.render('home')
})
200以外的状态码
app.get('/error',function(req,res){
res.status(500).render('error')
})
将上下文传递给视图,包括查询字符串,cookie和session
app.get('/greeting',function(req,res){
res.render('about',{
message:'welcome',
style:req.query.style,
userid:req.cookies.userid,
username:req.session.username
})
})
渲染纯文本输出
app.get('/test',function(req,res){
res.type('text/plain');
res.send('this is a test');
})
添加错误处理程序 注意这段应该要出现在所有路由方法的最后
app.use(function(err,req,res,next){
console.error(err.stack)
res.status(500).render('error')
})
404处理程序
app.use(function (req, res) {
res.status('404');
res.render('not-found')
})
7.2 处理表单
处理表单时一般在req.body中,可以使用req.xhr来判断是AJAX请求还是浏览请求
示例如下 如果是ajax则回传一个对象,否则重定向到对应的html
app.post('/process-contact', function (req, res) {
console.log('received contact from' + req.body.name + '<' + req.body.email + '>');
try {
//业务逻辑
return res.xhr ? res.render({ success: true }) : res.redirect(303, 'thank-you')
} catch (ex) {
return res.xhr ? res.json({ error: 'Database error' }) : res.redirect(303, '/database-error')
}
})
7.3 旅行数据示例
通过res.format在接收不同的请求数据类型时做不同的处理
let tours = [
{ id: 0, name: 'Hood River', price: 99.99 },
{ id: 1, name: 'Oregon Coast', price: 149.99 }
]
app.get('/api/tours', function (req, res) {
let toursXml = '<?xml version="1.0"?><tours>' + tours.map(function (p) {
return '<tour price="' + p.price + '" id="' + p.id + '">' + p.name + '</tours>'
}).join('') + '</tours>';
res.format({
'application/json': function () {
res.json(tours)
},
'application/xml':function(){
res.type('application/xml')
res.send(toursXml)
},
'text/plain': function(){
res.type('text/plain');
res.send(toursXml);
}
})
})
更新put示例
app.put('/api/tour/:id', function (req, res) {
let p = tours.some(p => p.id == req.params.id)//根据id找到要修改的那条数据
if(p){
if(req.query.name) p.name = req.query.name; //对查询字符串进行处理
if(req.query.price) p.price=req.query.name;
}else{
res.json({error:'No such tour exists'})
}
})
删除数据示例
app.delete('/api/tour/:id',(req,res)=>{
for(let i=tours.length-1;i>=0;i--){
if(tours[i].id == req.params.id) break;//获取要删除
}
if(i>=0){
tours.splice(i,1);
res.json({success:true})
}else{
res.json({error:'no such tour exists'})
}
})