koajs成长之路--如何执行跳转redirect?

1,511 阅读2分钟

     Koajs官网有这么一句话。这包括诸如内容协商,缓存清理,代理支持和重定向等常见任务的方法。 尽管提供了相当多的有用的方法 Koa 仍保持了一个很小的体积,因为没有捆绑中间件。

     就是说Koajs核心库内置了跳转方法,如何执行跳转呢?大多数都会清楚的记得,使用ctx.redirect("url地址") 来进行跳转,这个方法执行了之后,页面就会进行跳转。

     我们说记住APi是一个程序员使用该框架的必须途径,但Koajs的学习之路,我们必须是通读源码的。现在我来问一个问题,如果你可以在不参考源码的前提下回答出来,那么这篇文章你就可以略过了,否则还是要继续的阅读源码,这是我挂在嘴边的一句话。

    什么问题呢?问:ctx.redirect("第一个参数未url地址","第二个参数alt的作用是什么呢")

什么,你犹豫了,你思考了,你彷徨了,那么请继续查看源码。我们打开源码,

  /**   * Perform a 302 redirect to `url`.   *
   * The string "back" is special-cased
   * to provide Referrer support, when Referrer
   * is not present `alt` or "/" is used.   *
   * Examples:   *   *    this.redirect('back');
   *    this.redirect('back', '/index.html');
   *    this.redirect('/login');
   *    this.redirect('http://google.com');
   *   * @param {String} url
   * @param {String} [alt] 
   * @api public   */
  redirect(url, alt) {
    // location
    // 如果url地址设置的是back  那么获取Referrer参数活设置的默认值 或/
    if ('back' === url) url = this.ctx.get('Referrer') || alt || '/';
    // header中设置参数Location
    this.set('Location', encodeUrl(url));
    // status
    // this.res.statusCode
    // 如果当前状态码为空 那么设置为302  临时重定向 默认的状态码为404
    if (!statuses.redirect[this.status]) this.status = 302;
    // html
    if (this.ctx.accepts('html')) {
      url = escape(url);
      this.type = 'text/html; charset=utf-8';
      this.body = `Redirecting to <a href="${url}">${url}</a>.`;
      return;    }
    // text
    this.type = 'text/plain; charset=utf-8';
    this.body = `Redirecting to ${url}.`;
  },

查看源码,依照我添加的注释,可以看到redirect包含了很多的知识点,我们来逐行分析下:

    // 如果url地址设置的是back  那么获取Referrer参数活设置的默认值 或/
    if ('back' === url) url = this.ctx.get('Referrer') || alt || '/';

如果url地址我们设置为back,那么首先从Referrer中获取值,如果获取不到,使用alt参数,如果仍然为空,那么取“/”。

思考下,何时我们才想将url设置为back呢,答案就是回退,如果我们想回退到上一个地址,那么我们可以将url地址设置为back。

那么回退有没有限制呢?答案是有,而且还不少,首先就是referrer 我们是否设置,referrer是什么呢?referrer其实就是我们通过超链接跳转到该请求,浏览器会自动添加该请求头。请注释是超链接,其他的请求方式,浏览器不会自动添加该请求头的。

如果不是通过超链接跳转过来的请求,那么如果我们设置了alt,那么会跳转到我们制定的地址,如果我们也没有制定alt,那么会回退到首页,即"/"。

看懂了这句代码的含义,我们才真正知道,我们应该什么时候传递alt参数,你get到了吗?

    // header中设置参数Location
    this.set('Location', encodeUrl(url));

该句代码的含义是在响应头中设置Location为我们获取到的待跳转地址。

看到此处,你可能会想,该方法没有对Url地址的为空判断呢,如果我们传递的Url地址为空,会发生什么呢?留给你分析下吧,其实如果设置为空,那么会在浏览器显示一个跳转语句,但未执行任何跳转。

不知道,这句代码你有没有想过另一个问题,我们的跳转其实是依赖往响应头中添加Location,进而浏览器自己进行的跳转,而不像其他后端语言,直接改变Url的请求地址进行跳转。

    // status
    // this.res.statusCode
    // 如果当前状态码为空 那么设置为302  临时重定向 默认的状态码为404
    if (!statuses.redirect[this.status]) this.status = 302;

这句代码比较简单些,就是查看我们当前的响应状态码是不是redirect中包含的,如果不是 那么设置为302。看到这里,好奇的小伙伴会问,究竟哪些状态码是redirect的呢?调试起来,我们看到就是300包含的几个状态码。

看到这里,我们应该思考下,为什么我们设置了Location,还要设置必须是redirect的状态码?这就涉及到浏览器跳转的一个知识点,浏览器查看Location要执行跳转,状态码必须是redirect的,浏览器才会自动执行跳转,否则浏览器会忽略该Location,不会执行跳转。

    // html
    if (this.ctx.accepts('html')) {
      url = escape(url);
      this.type = 'text/html; charset=utf-8';
      this.body = `Redirecting to <a href="${url}">${url}</a>.`;
      return;    }
    // text
    this.type = 'text/plain; charset=utf-8';
    this.body = `Redirecting to ${url}.`;

这几句代码,就不过多的说明,主要是设置body的值。

那么回头上面我们说的问题,如果url我们传递空值,并且状态码设置了redirect的状态码,那么浏览器究竟会如何响应呢?

我们来实地操作下,最终的答案是界面显示了一个Redirecting to .

那么答案来了,我如果想显示其他更有意义的界面,如何操作呢?

针对源码中的很多细节,我们要仔细分析,才能更好的使用它,或者让他为我所用。