所有的好的Web框架都有一套好的通道截拦的机制,Nancy在我看来是处理最好的。那什么是请求通道那?下面的图可能说的比较清楚些:

正如名称中描述的,一个典型的Web请求在到达最终响应前会穿过一定数量的模块,然后反向通过这些模块到达浏览器。

请求到底要经过多少类型的模块需要根据框架而定。有的多,有的少。越多的处理,响应的就越慢。

定位一个轻量级和模块化的Web框架,它的通道中有很少的环节,使得开发人员可以更好的控制模块如何、在什么情况下可以与框架进行交互。

当我们谈论通道截拦的时候,主要是指Nancy公开的几个主要回调点(钩子函数),使得你可以在请求链的回调点加入你自己的模块或代码段。

到目前为止,你可以见到了Nancy众多的功能 -- 身份验证就是一个好的例子。 -- 你可能会想在通道处理中会需要很多代码量来支撑这个功能。

事实是,Nancy基本上没有在身份验证方面编写什么代码,即使你调用身份验证的方法,在通道中也不会添加什么代码处理。只有在你添加了this.RequiresAuthentication();行后,请求通道才会进行身份验证截拦。

验证部分也就是注册了路由模块的Before 和 After 管道,让我们看下面的验证校验页面:

using Nancy;
using Nancy.Responses;
using Nancy.Security;
namespace nancybook.modules
{
public class AuthRoutes : NancyModule
{
public AuthRoutes() : base("/auth")
{
Before += ctx =>
{
return (this.Context.CurrentUser == null)
? new HtmlResponse(HttpStatusCode.Unauthorized)
: null;
};
Get[@"/"] = _ => View["auth/index"];
}
}
}

上面的处理其实和 RequiresAuthentication 的功能是一样的。

通过这一段代码,你可以很清晰的看到两种结果。首先可能会返回null, 这不会影响到处理进程,其实是不会有什么影响。

再者就是返回一个响应对象(例子中是 403 Unauthorized),进程不会再往下执行,而是直接返回给客户端。

  当然你可能已经意识到这不仅能用于身份验证,还可以做一些资源的检查,其他条件的校验或者返回异常信息等不一样的结果。

假如你想提供某种形式的前端缓存,例如 你可以拦截 Before管道,判断请求是否已经缓存,如果已经缓存就返回缓存的版本。只有在没有缓存或缓存过期的时候访问路由模块的处理程序。

你也可以像下面提供After处理:

After += ctx =>
{ //... Code here ...
}

在启用After管道的时候,你已经可以访问到相应对象了(路由处理程序生成的),通过Nancy上下文就可以对它进行随意的修改。

比如你可以检查一些环境变量,在返回到浏览器前可以修改已经生成的200 ok 的相应为403响应。

我想,你可以更加倾向于使用After管道来缓存客户端请求,下次相同请求就可以查找预先的缓存,而不是再一次到数据库中读取。

值得注意的是附加在路由模块上的代码会在该模块的每次请求中调用,这也就意味着你的代码要耗时长一点,客户端的请求响应速度会被减缓。

应用级别的挂接

你也可以在整个应用级别上注册Before或After管道,而不只是在模块基础上。启用应用级别的意味着每个模块、每个路由都会触发注册的挂接,无论怎么定义。另外,如果你注册了一个应用级的挂接,并在一个特殊的模块上也单独做了注册挂接,两个挂接都会被调用,应用级的优先。

这也意味着在应用级别的挂接上返回一个响应对象,模块级别的挂接就不再会被调用。同理,模块级别的挂接返回了响应对象,模块的处理也就不会被调用。

你可以定义一个bootstrapper ,重载ApplicationStartup 或RequestStartup 方法来注册应用级别的挂接。这两个方法会暴露一个Pipelines 参数,它包含BeforeRequest 或AfterRequest 属性,可以像使用Before 或After挂接一样来看待。

你也将会使用到OnError属性,可以用来在应用系统中实现一个异常处理程序。举个例子,在你的数据库检索代码中,如果检索不到一条客户端请求的记录,你可以会抛出一个Database Object not found 的自定义异常。你可以使用自定义的bootstrapper
    来拦截这个异常,然后返回一个404 文件未找到异常,就类似下面:

using System.Text;
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.Conventions;
using Nancy.Session;
using Nancy.TinyIoc;
namespace nancybook
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(
TinyIoCContainer container,
IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
// Add an error handler to catch our entity not found exceptions
pipelines.OnError += (context, exception) =>
{
// If we've raised an EntityNotFound exception in our data layer
if (exception is EntityNotFoundException)
return new Response()
{
StatusCode = HttpStatusCode.NotFound,
ContentType = "text/html",
Contents = (stream) =>
{
var errorMessage = Encoding.UTF8.GetBytes("Entity not
found");
stream.Write(errorMessage, , errorMessage.Length);
}
};
// If none of the above handles our exception, then pass it on as a 500
           throw exception; 
};
}
}
}

   输出缓存

using System;
using System.Collections.Specialized;
using System.Runtime.Caching;
using Nancy;
namespace nancybook
{
public class CacheService
{
private static readonly NameValueCollection _config = new
NameValueCollection();
private readonly MemoryCache _cache = new MemoryCache("NancyCache",
_config);
private readonly CacheItemPolicy _standardPolicy = new CacheItemPolicy
{
Priority = CacheItemPriority.NotRemovable,
SlidingExpiration = TimeSpan.FromSeconds() // This can be changed };
public void AddItem(string itemKey, Response itemToAdd)
{
_cache.Add(new CacheItem(itemKey, itemToAdd), _standardPolicy);
}
public Response GetItem(string itemKey)
{
return (Response)_cache.Get(itemKey);
}
}
}
protected override void ConfigureApplicationContainer(TinyIoCContainer
container)
{
base.ConfigureApplicationContainer(container);
container.Register<CacheService>().AsSingleton();
}
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using nancybook.Models;
using Nancy;
namespace nancybook.modules
{
public class CachingRoutes : NancyModule
{ readonly CacheService _myCache;
public CachingRoutes(CacheService myCache) : base("/caching")
{
_myCache = myCache;
Get["/"] = x =>
{
var cacheData = new CacheDemo() {WhenRequested = DateTime.Now};
return View["caching/index.html", cacheData];
};
Before += ctx =>
{
string key = ctx.Request.Path;
var cacheObject = _myCache.GetItem(key);
return cacheObject;
};
After += ctx =>
{
if(ctx.Response.StatusCode != HttpStatusCode.OK)
{
return;
}
string key = ctx.Request.Path;
if(_myCache.GetItem(key) == null)
_myCache.AddItem(key, ctx.Response);
};
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nancy Demo | Caching Example</title>
<link href="~/content/bootstrap.min.css" rel="stylesheet"
type="text/css"/>
</head>
<body>
<div class="container">
<div class="page-header">
<h1 style="display: inline-block">Nancy Demo <small>Caching
Example</small></h1>
<h1 style="display: inline-block" class="pull-right"><small><a
href="~/" title="Click to return to demo home page">home <span
class="glyphicon glyphicon-home"></span></a></small></h1>
</div>
<h4>This page was requested at <strong class="textsuccess">@Model.WhenRequested</strong></h4>
<br/><br/>
<p class="lead">This example uses before and after filters attached
directly to the module servicing this request.</p>
<p>If you observe the time this page was created when refreshing it,
you'll see the page is handled by an output cache; this cache has a sliding
window of seconds.</p>
<p>
As long as you’re refreshing the page, you'll reset the timer and the
cache will continue to wait seconds after the last request before
expiring. If you request the page then
leave it for seconds before re-requesting it, you'll see you get a
new copy.
</p>
</div>
<script src="~/scripts/jquery-2.1.3.min.js"></script>
<script src="~/scripts/bootstrap.min.js"></script>
</body>
</html>

CacheDemo.cs

using System;
namespace nancybook.Models
{
public class CacheDemo
{
public DateTime WhenRequested { get; set; }
}
}

总结

NancyFX 第十二章 通道截拦的更多相关文章

  1. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader)

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader) 代码工 ...

  2. PRML读书会第十二章 Continuous Latent Variables(PCA,Principal Component Analysis,PPCA,核PCA,Autoencoder,非线性流形)

    主讲人 戴玮 (新浪微博: @戴玮_CASIA) Wilbur_中博(1954123) 20:00:49 我今天讲PRML的第十二章,连续隐变量.既然有连续隐变量,一定也有离散隐变量,那么离散隐变量是 ...

  3. <构建之法>第十一章、十二章有感

    十一章:软件设计与实现 工作时要懂得平衡进度和质量.我一直有一个困扰:像我们团队这次做 男神女神配 社区交友网,我负责主页的设计及内容模块,有个队友负责网站的注册和登录模块,有个队友负责搜索模块,有个 ...

  4. sql 入门经典(第五版) Ryan Stephens 学习笔记 (第六,七,八,九,十章,十一章,十二章)

    第六章: 管理数据库事务 事务 是 由第五章 数据操作语言完成的  DML ,是对数据库锁做的一个操作或者修改. 所有事务都有开始和结束 事务可以被保存和撤销 如果事务在中途失败,事务中的任何部分都不 ...

  5. 《Linux命令行与shell脚本编程大全》 第二十二章 学习笔记

    第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系后代,ash shell是Unix系统上原来地Bourne shell的简化版本 ...

  6. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  7. [CSAPP笔记][第十二章并发编程]

    第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...

  8. perl5 第十二章 Perl5中的引用/指针

    第十二章 Perl5中的引用/指针 by flamephoenix 一.引用简介二.使用引用三.使用反斜线(\)操作符四.引用和数组五.多维数组六.子程序的引用  子程序模板七.数组与子程序八.文件句 ...

  9. 第十二章——SQLServer统计信息(4)——在过滤索引上的统计信息

    原文:第十二章--SQLServer统计信息(4)--在过滤索引上的统计信息 前言: 从2008开始,引入了一个增强非聚集索引的新功能--过滤索引(filter index),可以使用带有where条 ...

随机推荐

  1. maven使用jstl表达式和The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application解决

    maven 中使用jstl表达式中出现如上错误.原因: 1.由于在maven中的web项目没有自动依赖jstl的jar 未在pom文件中添加jstl相关的jar <!--jstl表达式--> ...

  2. DAY2-JAVA

    2018-1-28学习笔记 1.在开发中定义类.方法时也可以先添加文档注释,再用javadoc工具生成自己的API文档.Java文档注释和java工具使用. 2.掌握查阅java JDK和API文档. ...

  3. 4.3 lambda表达式

    函数,封装的代码块可以很复杂,也可以很简单.当函数的代码块简单到只有一个表达式,就可以考虑用lambda表达式,也称匿名函数. 1 lambda表达式基础 #首先需要声明一点:lambda是表达式而非 ...

  4. 使用Socket对序列化数据进行传输(基于C#)

    客户端代码 [Serializable] // 表示该类可以被序列化 class Person{ public string name; public void HI() { Debug.Log(na ...

  5. openresty+lua劫持请求,有点意思

    0x01 起因 几天前学弟给我介绍他用nginx搭建的反代,代理了谷歌和维基百科. 由此我想到了一些邪恶的东西:反代既然是所有流量走我的服务器,那我是不是能够在中途做些手脚,达到一些有趣的目的. op ...

  6. MongoDB,子查询

    //1.从sub(订单明细)对订单号分组,查询最多子订单的单号一条数据,重命名orderNo字段为num//2.根据这个sub.num(从结果集里获取第一条结果),查询main(主档表) db.mai ...

  7. GOF23种设计模式精解

    创建型 1. Factory Method(工厂方法) 2. Abstract Factory(抽象工厂) 3. Builder(建造者) 4. Prototype(原型) 5. Singleton( ...

  8. mysql常用基础操作语法(二)~~对表的增删改操作【命令行模式】

    1.修改表名:alert table oldtablename rename newtablename; 或者alert table oldtablename rename to newtablena ...

  9. table行随鼠标变色

    table行随鼠标变色 1.设计表格 <body class="html_body"> <div class="body_div"> & ...

  10. Linux查看非root运行的进程

    Linux查看非root运行的进程 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ps -U root -u root -N PID TTY TIME CMD ...