Better

Ethan的博客,欢迎访问交流

Node与Express开发之请求和响应对象

最近准备系统的学习Node和Express,学习笔记-请求和响应对象篇!请求对象和响应对象是HTTP请求中至关重要的一环,在这里分出来重点记录,主要内容有URL的组成、请求方法、报头分析以及请求和响应对象等。

Express构建Web服务器时,大部分的工作都是从请求对象开始,到响应对象终止。这两个对象起源于Node,Express对其进行了扩展。探讨这两个对象时,我们先看看客户端如何向服务器请求一个页面,以及页面是如何返回的。

URL组成部分

URL的组成部分和含义如下:

  • 协议
    协议确定如何传输请求,主要处理http和https。其他常见的协议还有file和ftp。
  • 主机名
    主机名标识服务器,在Internet环境下,主机名通常以一个顶级域名结尾,比如.com或.net等。此外也许还会有子域名作为主机名的前缀。子域名可以是任何形式的,其中www最为常见。子域名通常是可选的。
  • 端口
    每台服务器都有一系列端口号,如果省略端口号,那么默认80端口负责http传输,443端口负责https传输。,如果不使用默认端口,那么需要一个大于1023的端口号(0—1023为知名端口,容易冲突)。
  • 路径
    URL中影响应用程序的第一个组成部分通常是路径。路径是应用中的页面或其它资源的唯一标识。
  • 查询字符串
    查询字符串是一种键值对集合,是可选的。以问号(?)开始,键值对则以与号(&)分隔开。所有的名称和值都必须是URL编码的,对此JavaScript提供了一个嵌入式函数encodeURIComponent来处理。例如空格被加号(+)替换。其他特殊字符被数字型字符替换。
  • 信息片段
    也叫散列,被严格限制在浏览器中使用,不会传递到服务器。用它控制单页应用或AJAX富应用越来越普遍。起初,信息片段只是用来让浏览器展现文档中通过锚点标志指定的部分。

请求方法

HTTP协议确定了客户端与服务器通信的请求方法的集合,通常称为HTTP verbs。其中GET和POST最常见。

对于一个网站而言,大部分页面都响应GET请求,POST请求通常用来提交表单信息到服务器后台。与服务器通信时,浏览器只使用GET和POST方法(如果没有使用AJAX);

另一方面,网络服务通常通常会使用更多的创造性HTTP方法,比如PUT,DELETE等。

请求报头

客户端请求发送到服务器的并不只是URL,当你访问一个网站时,浏览器会发送很多隐形信息。服务器因此会得到优先响应哪种语言,同时也会发送用户代理信息(浏览器、操作设备和硬件设备)和一些其他信息。所有能够确保你了解请求对象头文件属性的信息都将会作为请求报头发送。服务器端可以用过req.headers得到所有头信息。

响应报头

正如浏览器以请求报头的形式发送隐藏信息到服务器,当服务器响应时,同样会回传一些浏览器没必要渲染和显示的信息,通常是元数据和服务器信息。比如:

  • 内容类型 - 告诉浏览器正在被传输的内容类型,不管URL路径是什么,浏览器都根据内容类型报头处理信息。
  • 内容是否压缩
  • 编码
  • 关于浏览器对资源缓存时长的显示 - 优化网站是需要考虑这点
  • 服务器信息 - 服务器类型,操作系统信息
    返回服务器信息存在一个问题,那就是他会给黑客一个可乘之机,从而使站点陷入危险。非常重视安全的服务器经常忽略此信息,甚至提供虚假信息。进入Express的X-Powered-By头信息很简单:
    app.disable('X-Powered-By');
    

互联网媒体类型

内容类型报头信息极其重要,没有它,客户端很难判断如何渲染接收到的内容。内容类型就是一种互联网媒体类型,由一个类型、一个子类型以及可选的参数组成。例如text/html;charset=UTF-8说明类型是text,子类型是html,字符编码是UTF-8。我们常见的content typeInternet media typeMIME type是可以互换的。

请求体

除了请求报头外,请求还有一个主体,就像作为实际内容返回的响应主体一样,一般GET请求没有,但是POST请求是有的。POST请求常见的媒体类型如下:

  • application/x-www-form-urlencoded:键值对集合的简单编码,基本上和查询字符串格式一样
  • multipart/form-data:支持文件上传,一种更复杂的格式
  • application/json:Ajax请求

参数

参数可以有很多中解释,对于任何一个请求,参数可以来源如下:

  • 查询字符串
  • 会话
  • 请求体
  • 路由参数

请求对象

请求对象,通常传递到回调方法中,因此可以随意命名。通常命名为req或request,请求对象的生命周期始于Node的核心对象http.IncomingMessage实例。Express扩展了一些附加功能。看看请求对象中最有用的属性和方法(除了req.headers和req.url),所有这些方法都由Express添加。

  • req.params - 路由参数
  • req.query - 查询字符串参数
  • req.body - 一个对象包含POST请求参数,要使req.body可用,需要中间件能够解析请求正文内容类型
  • req.route - 当前匹配的路由信息
  • req.cookies/req/singnedCookies - cookies值
  • req.headers - 请求报头
  • req.ip
  • req.path - 路径
  • req.host - 返回客户端所报告的主机名,信息可以伪造,因此不应该用于安全目的
  • req.xhr - ajax请求将返回true
  • req.protocal
  • req.secure - 等同于req.protocal === 'https'
  • req.url/req.originalUrl - 返回路径和查询字符串
  • req.acceptedLanguages - 返回客户端首选的一组语言,从请求报头中解析而来

响应对象

响应对象,通常传递到回调方法中,意味着你可以随意命名它,通常命名为req、resp或response,响应对象的生命周期始于Node核心对象http.ServerResponse的实例。在这里看看响应对象中最有用的属性和方法,所有这些方法都由Express添加的!

  • res.status(code) - Express默认200,你可以使用这个方法返回404或500或任何其他的状态码。对于重定向(301,302,303和307),推荐更好的方法:redirect
  • res.set(name,value) - 设置响应头
  • res.cookie(name,value,[options])/res.clearCookie(name,[options]) - 设置或清除客户端cookie,需要中间件支持
  • res.redirect([status],url) - 重定向浏览器,默认302
  • res.send(body),res.send(status,body) - 向客户端发送响应及可选的状态码。Express默认内容类型是text/html。如果body是对象或数组,响应将会以JSON发送(内容类型需要被正确设置),不过这时更推荐直接使用res.json。
  • res.json(json),res.json(status,json) - 发送json以及可选的状态码。
  • res.type(type) - 一个简便的方法,用于设置Content-Type头信息,基本上相当于res.set('Content-Type',type)如果你提供了一个没有斜杆的字符串,它会试图把其当做文件的扩展名映射为一个互联网媒体类型。比如txt会映射为text/plain。
  • res.format(object) - 允许你根据接受请求报头发送不同的内容。res.format({'text/plain':'hi there','text/html':'<b>hi there</b>'})
  • res.attachment([filename]),res.download(path,[filename],[callback])
    • 这两种方法会将响应报头Content-Disposition设置为attachment,这样浏览器就会选择下载而不是展示内容。
    • filename给浏览器作为对用户的提示
    • res.download指定要下载的文件,而res.attachment只设置报头,此外还要将内容发送到客户端。
  • res.sendFile(path,[option],[callback]) - 根据路径读取指定文件并在内容发送到客户端
  • res.locals,res.render(view,[locals],[callback])
    • res.locals是一个对象,包含用于渲染视图的默认上下文
    • res.render使用配置的模板引擎渲染视图,默认响应码200

总结

大部分的时候我们只需要用到其中一小部分,因此我们根据使用的频繁程度将其分解开来。

内容渲染

内容渲染最常用的就是res.render,他们最大程度地根据布局渲染视图。综合例子如下:

app.get('/greeting',function(req,res){
    res.render('about',{
        message:'welcome',
        style:req.query.style,
        userid:req.cookie.userid,
        username:req.session.username
    })
});

处理表单

当你处理表单时,表单信息一般在req.body中,你可以使用req.xhr来判断是AJAX请求还是浏览请求。

// 必须引入body-parser
app.post('/contact',function(req,res){
    console.log(req.body.name);
    try{
        return req.xhr ? res.json({success:true}) : res.redirect(303,'/thank-you');
    }catch(e){
        return req.xhr ? res.json({error:'error'}) : res.redirect(303,'/error');
    }
})

提供API

在这里你经常使用不太常见的HTTP动词。比如PUT,DELETE等。

app.put('/api/tour/:id',function(req,res){
    // req.params.id
})


留言