NancyFX 第十二章 通道截拦
所有的好的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 第十二章 通道截拦的更多相关文章
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader)
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十二章:几何着色器(The Geometry Shader) 代码工 ...
- PRML读书会第十二章 Continuous Latent Variables(PCA,Principal Component Analysis,PPCA,核PCA,Autoencoder,非线性流形)
主讲人 戴玮 (新浪微博: @戴玮_CASIA) Wilbur_中博(1954123) 20:00:49 我今天讲PRML的第十二章,连续隐变量.既然有连续隐变量,一定也有离散隐变量,那么离散隐变量是 ...
- <构建之法>第十一章、十二章有感
十一章:软件设计与实现 工作时要懂得平衡进度和质量.我一直有一个困扰:像我们团队这次做 男神女神配 社区交友网,我负责主页的设计及内容模块,有个队友负责网站的注册和登录模块,有个队友负责搜索模块,有个 ...
- sql 入门经典(第五版) Ryan Stephens 学习笔记 (第六,七,八,九,十章,十一章,十二章)
第六章: 管理数据库事务 事务 是 由第五章 数据操作语言完成的 DML ,是对数据库锁做的一个操作或者修改. 所有事务都有开始和结束 事务可以被保存和撤销 如果事务在中途失败,事务中的任何部分都不 ...
- 《Linux命令行与shell脚本编程大全》 第二十二章 学习笔记
第二十二章:使用其他shell 什么是dash shell Debian的dash shell是ash shell的直系后代,ash shell是Unix系统上原来地Bourne shell的简化版本 ...
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高
第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...
- [CSAPP笔记][第十二章并发编程]
第十二章 并发编程 如果逻辑控制流在时间上是重叠,那么它们就是并发的(concurrent).这种常见的现象称为并发(concurrency). 硬件异常处理程序,进程和Unix信号处理程序都是大家熟 ...
- perl5 第十二章 Perl5中的引用/指针
第十二章 Perl5中的引用/指针 by flamephoenix 一.引用简介二.使用引用三.使用反斜线(\)操作符四.引用和数组五.多维数组六.子程序的引用 子程序模板七.数组与子程序八.文件句 ...
- 第十二章——SQLServer统计信息(4)——在过滤索引上的统计信息
原文:第十二章--SQLServer统计信息(4)--在过滤索引上的统计信息 前言: 从2008开始,引入了一个增强非聚集索引的新功能--过滤索引(filter index),可以使用带有where条 ...
随机推荐
- 高可用的MongoDB集群
1.序言 MongoDB 是一个可扩展的高性能,开源,模式自由,面向文档的数据库. 它使用 C++编写.MongoDB 包含一下特点: l 面向集合的存储:适合存储对象及JSON形式的数据. l ...
- Java经典编程题50道之二十七
求100之内的素数. public class Example27 { public static void main(String[] args) { prime(); } ...
- PHP文件头BOM头问题
前几天我们公司服务器出现了一个离奇的问题,服务器与本地文件代码完全一致,本地运行正常,到了测试环境服务器之后,各种问题一个又一个浮现,先是后台验证码不显示,以为是session写入失败,又是怀疑gd库 ...
- Android 如何进行页面传递对象
当我们从一个页面调到另一个页面的时候,需要把该页面的一些设定值也传递给下一个页面.当要传递的值很多时,我们可以传递一个对象. 页面1: Intent intent = new Intent(PageO ...
- UVA - 10723 类似LCS
思路:dp(i, j)表示第一个串前i个字符和第二个串前j个字符需要的最短字符串长度,cnt(i, j)表示第一个串前i个字符和第二个串前j个字符需要的最短字符串的个数. 转移方程: if(s1[i] ...
- CodeForces - 730A 贪心+模拟
贪心策略: 1.只有一个最大值,选着第二大的一起参加比赛减分. 2.有奇数个最大值,选择三个进行比赛. 3.偶数个最大值,选择两个进行比赛. 为什么不把最大值全部选择? 因为最多只能选五个,有可能选择 ...
- 记录一下html渲染页面的 js框架
1.artTemplate 2.laytpl 3.juicer 4.doT 5.Mustache 6.Handlebars 7.baiduTemplate 8.KissyTemplate 详细的以后补 ...
- cips2016+学习笔记︱简述常见的语言表示模型(词嵌入、句表示、篇章表示)
在cips2016出来之前,笔者也总结过种类繁多,类似词向量的内容,自然语言处理︱简述四大类文本分析中的"词向量"(文本词特征提取)事实证明,笔者当时所写的基本跟CIPS2016一 ...
- 3.3.2 PCI设备对不可Cache的存储器空间进行DMA读写
在x86处理器和PowerPC处理器中,PCI设备对"不可Cache的存储器空间"进行DMA读写的过程并不相同.其中PowerPC处理器对"不可Cache的存储器空间&q ...
- 3.3 与Cache相关的PCI总线事务
PCI总线规范定义了一系列与Cache相关的总线事务,以提高PCI设备与主存储器进行数据交换的效率,即DMA读写的效率.当PCI设备使用DMA方式向存储器进行读写操作时,一定需要经过HOST主桥,而H ...