首页 文章 精选 留言 我的

精选列表

搜索[融合分析],共10000篇文章
优秀的个人博客,低调大师

squid 日志分析 - hadoop hive

#!/usr/bin/env python #-*-coding:UTF-8-*- """ @Item : Hadoop analysis squid log @Author : Villiam Sheng @Group : Linux Group @Date : 2012-09-13 @Funtion: Use hadoop squid processing log ...................... """ import os,re,threading,tarfile,shutil,time,sys,datetime import sys,traceback sys.path.append('/usr/local/hive/lib/py') from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from hive_service import ThriftHive from hive_service.ttypes import HiveServerException class split_log(threading.Thread): def __init__(self,files,lock): threading.Thread.__init__(self) self.files = files self.path = '/data1/squid_log' self.lock = lock def log(self,info): files = open('%s/split_log'%self.path,'a') try: files.write(info) except IOError: files.close() files.close() size = os.path.getsize('%s/split_log'%self.path) / 1024 if size >= 1024: fp = open('%s/split_log'%self.path,'w') fp.write('') fp.close() def run(self): try: if not os.path.isdir(self.files): tar = tarfile.open('%s/%s'%(self.path,self.files)) for name in tar.getnames(): tar.extract(name,'/%s/%s/'%(self.path,self.files.split('.tgz')[0])) tar.close() self.log('%s file:%s run.info:tar done \n'%(time.ctime(),self.files)) except Exception,e: self.log('%s files:%s run.info:%s \n'%(time.ctime(),self.files,e)) try: fp = open('%s/%s/access.log.0'%(self.path,self.files.split('.tgz')[0]),'r') for i in fp.readlines(): b = i.split() fps = open('%s/%s/tmp.log'%(self.path,self.files.split('.tgz')[0]),'a+') fps.write("%s\t%s\t%s\t%s\t%s\n" %(datetime.datetime.strptime(b[3].split('[')[1],'%d/%b/%Y:%H:%M:%S').strftime('%Y%m%d%H%M%S'),b[0],i.split('/')[4],b[-5],b[-1])) fps.close() fp.close() except Exception,e: self.log('%s file:%s inert.info:insert done \n'%(time.ctime(),self.files.split('.tgz')[0])) try: asql="load data local inpath \'%s/%s/tmp.log\' overwrite into table squid.squid_tmp partition(pt_ip = \'%s\')" %(self.path,self.files.split('.tgz')[0],self.files.split('.tgz')[0]) self.lock.acquire() transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() try: client.execute(asql) except: pass transport.close() self.lock.release() os.remove ('%s/%s'%(self.path,self.files)) shutil.rmtree('%s/%s' %(self.path,self.files.split('.tgz')[0])) except: self.log('Exception error : %s '%traceback.print_exc()) def work(): ip_list = re.compile('^(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))$') lock = threading.RLock() for i in os.listdir('/data1/squid_log/'): if not ip_list.match(i.split('.tgz')[0]): continue st = split_log(i,lock) st.start() while threading.active_count() != 1: time.sleep(1) transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() client.execute("use squid") client.execute("set hive.exec.dynamic.partition=true") client.execute("set hive.exec.dynamic.partition.mode=nonstrict") sql = "insert into table squid_log partition(pt_ip, pt_dt) select visittime, clientip, visitdom, visiturl, visitstat, pt_ip, substr(visittime, 1, 8) as pt_dt from squid_tmp" client.execute(sql) transport.close() if __name__ == "__main__": try: pid = os.fork() if pid > 0 : sys.exit(0) os.setsid() os.chdir('/') sys.stdin = open("/dev/null","r+") sys.stdout = os.dup(sys.stdin.fileno()) sys.stderr = os.dup(sys.stdin.fileno()) while True: work() time.sleep(300) work() except: pass 本文转自 swq499809608 51CTO博客,原文链接:http://blog.51cto.com/swq499809608/1142212

优秀的个人博客,低调大师

squid 日志分析 - hive 删除

#!/usr/bin/env python #-*-coding:utf8-*- import os,re,threading,tarfile,shutil,time,sys,datetime import sys,traceback sys.path.append('/usr/local/hive/lib/py') from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from hive_service import ThriftHive from hive_service.ttypes import HiveServerException transport = TSocket.TSocket('127.0.0.1',10000) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = ThriftHive.Client(protocol) transport.open() client.execute("use squid") class threads_del(threading.Thread): def __init__(self,pt_ip,pt_dt): threading.Thread.__init__(self) self.pt_ip = pt_ip self.pt_dt = pt_dt def run(self): client.execute("set hive.exec.dynamic.partition=true") client.execute("set hive.exec.dynamic.partition.mode=nonstrict") sql = "alter table squid_log drop partition(pt_ip = '%s', pt_dt=%s)"%(self.pt_ip,self.pt_dt) client.execute(sql) def work(): client.execute('show partitions squid_log') info = client.fetchAll() infos = {} for i in info: a = re.split("/",i) try: infos[re.split("=",a[0])[1]].append(re.split("=",a[1])[1]) except: infos[re.split("=",a[0])[1]] = [] infos[re.split("=",a[0])[1]].append(re.split("=",a[1])[1]) for k,v in infos.items(): st = threads_del(k,min(v)) st.start() st.join() while threading.active_count() >1: time.sleep(1) transport.close() if __name__ == "__main__": st = work() 本文转自 swq499809608 51CTO博客,原文链接:http://blog.51cto.com/swq499809608/1142457

优秀的个人博客,低调大师

uboot移植之主Makefile分析

1:#uboot 的版本号 VERSION = 1 #主版本号 PATCHLEVEL = 3 #次版本号 SUBLEVEL = 4 #再次版本号 EXTRAVERSION = #关于uboo的一些另外的描述 #变量U_BOOT_VERSION用来保存uboot的版本信息 U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) VERSION_FILE = $(obj)include/version_autogenerated.h //存放变量U_BOOT_VERSION,也就是版本信息 # 这个文件是编译时产生的中间文件include/version_autogenerated.h,这个文件的内容为 #define U_BOOT_VERSION "U-Boot 1.3.4"。 2:HOSTARCH(主机架构)和HOSTOS(主机操作系统) HOSTARCH := $(shell uname -m | \ sed -e s/i.86/i386/ \ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ \ -e s/sa110/arm/ \ -e s/powerpc/ppc/ \ -e s/ppc64/ppc/ \ -e s/macppc/ppc/) HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ sed -e 's/\(cygwin\).*/cygwin/') export HOSTARCH HOSTOS (1)shell uname -m,脚本执行的方法,可以通过shell + 命令来直接执行, uname -m表示获取主机架构 (2)| 表示管道,前面的表达式的结果作为后面表达式的一个输入,从而得到最终的输出,这里也就是shell uname -m得到的结果通过管道作为 sed -e的输入。 (3)sed -e 直接在命令模式下进行sed的动作,s 表示替代。所以这部分的意识就是,通过执行uname -m来获取主机的架构,然后通过管道的方法根据主机的架构来得到我们需要的主机架构,比如,我的主机架构是i686,那么sed -e s /i.86/i386,所以HOSTARCH := i386。(:=表示覆盖之前的内容) (4)uname -s 表示获取操作系统的名字 ,我们在ubuntu下开发,所以操作系统就是Linux,然后通过tr '[:upper:]' '[:lower:]'将大写字母改为小写,也就是HOSTOS := linux 3:ifeq (,$(findstring s,$(MAKEFLAGS))) XECHO = echo else XECHO = : endif 判断是否为静默编译,静默编译就是不在控制台打印Makefile里面的信息,但是其他文件的信息还是会被打印出来。 $(findstring s,$(MAKEFLAGS)的意思是在MAKEFLAGS查找字符 s ,也就是假如我们编译的时候输入的是 make -s 则为静默编译。 4:ifdef O ifeq ("$(origin O)", "command line") BUILD_DIR := $(O) endif endif 原地编译或者是单独文件编译, 单独文件编译实现的方法有两种 (1)通过make O = xxx(输出文件的pathname)来实现,主要这种方式在我们配置和清除的时候也要添加 O = xxx,也就是 make distclean O = xxx make x210_sd_config O = xxx make O = xxx (2)通过定义 export BUILD_DIR=xxx(输出文件的pathname)来实现, O=xxx的优先级高于export BUILD_DIR=xxx 5:OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) #输出文件目录 SRCTREE := $(CURDIR) #当前目录,Makefile的当前目录也就是uboot的根目录 TOPDIR := $(SRCTREE) #顶层目录 LNDIR := $(OBJTREE) #链接文件目录 export TOPDIR SRCTREE OBJTREE 根据上面选择的是原地编译还是单独文件编译来确定并且导出这几个环境变量,用于后面使用,当选择原地编译时OBJTREE = SRCTREE OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR)) 如果 (if $(BUILD_DIR)为真(也就是BUILD_DIR被赋值)则OBJTREE = BUILD_DIR,否则OBJTREE = CURDIR。 6:MKCONFIG := $(SRCTREE)/mkconfig export MKCONFIG 定义并保存环境变量MKCONFIG。uboot根目录下的mkconfig文件是一个很重要的文件,uboot的配置就是根据这个文件的内容来实现的。 7:include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC 包含$(obj)目录下的include目录下的config.mk文件,这个文件的内容为 ARCH = arm CPU = s5pc11x BOARD = x210 VENDOR = samsung SOC = s5pc110 config.mk文件也是在配置的时候生成的 obj = OBJTREE,当原地编译的时候OBJTREE = SRCTREE = 源码根目录, 8:ifeq ($(ARCH),arm) #CROSS_COMPILE = arm-linux- #CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux- #CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux- CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- 通过ARCH的值来确定交叉编译工具链的前缀,CROSS_COMPILE的值其实就是交叉编译工具链的前缀。 9:include $(TOPDIR)/config.mk 添加根目录下的config.mk文件,这个文件的主要作用是 (1)补全交叉编译工具链,前面,在CROSS_COMPILE变量中我们保存了交叉编译工具链的前缀,其后缀就是在这个文件中补全的 (2)sinclude $(OBJTREE)/include/autoconf.mk:添加编译目录下的/include/autoconf.mk文件,这个文件是配置后生成的,里面全是CONFIG_开头的宏,这些宏定义左右着配置的uboot属于哪一款开发板。而这个文件的生成材料是顶层目录下的include/configs/xxx.h这个头文件,里面的一个头文件对应一款开发板,这个头文件的内容就是去描述或者说是配置这个开发板的硬件相关的信息。 (3)TEXT_BASE:链接地址的值 10:OBJS = cpu/$(CPU)/start.o,以及后面的LIBS = lib_generic/libgeneric.a等是在指定编译时需要添加的文件。 11:ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) $(obj)u-boot.dis ifeq ($(ARCH),blackfin) ALL += $(obj)u-boot.ldr all: $(ALL) $(obj)u-boot.hex: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ 当我们make编译的时候其实就是make all,当我们make all的时候又会生成类似于u-boot.hex的很多小目标,其中要注意的是最后一个目标unconfig unconfig: @rm -f $(obj)include/config.h $(obj)include/config.mk \ $(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \ $(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \ $(obj)board/$(VENDOR)/$(BOARD)/config.mk unconfig这个目标就是rm -f移除我们在配置的时候生成的配置文件,这也是我们在make x210_sd_config之后再次执行make x210_sd_config时得到的效果是一样的,原因就是x210_sd_config依赖于unconfig,unconfig而将我们之前配置的文件全部移除了。 12:x210_sd_config : unconfig @$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110 @echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk @表示静默执行 $(MKCONFIG) 表示引用MKCONFIG这个环境变量,也就是根目录下的mkconfig,并且向这个文件传递了$(@:_config=) arm s5pc11x x210 samsung s5pc110这6个参数。 当我们执行make x210_sd_config的时候其实就是执行了这里的x210_sd_config这个目标。 本文转自 菜鸟养成记 51CTO博客,原文链接:http://blog.51cto.com/11674570/1919951

优秀的个人博客,低调大师

MongoDB mapReduce案例分析一

例子1:找出集合中的所有键以及每个键对应的次数 MongoDB没有模式,所以并不知道每个文档有多少个键。通常找到集合中的所有键的最好方法就是利用MapReduce。好了,接下来看例子吧。 1、首先通过mongo->shell生成几条测试数据记录。 2、写map函数 3、写reduce函数 4、调用MapReduce看结果 5、查看结果 本文转自shayang8851CTO博客,原文链接:http://blog.51cto.com/janephp/1290604,如需转载请自行联系原作者

优秀的个人博客,低调大师

Spark 分析网站排名热度

需求: / 解决是一个各个子模块内的热度排名--》 排名得用sortBy ---》 (可能就是简单的排序,或者是二次排序) ---》 // 前面有一个wordCount---》 算出次数出来 --》 考虑什么作为key //算的一个网站下面,每个子模块下面的网页热度前2名 : // 算的一个网站下面,每个子模块下面的网页热度前2名 --》 每个子模块下面的网页的次数的前2名 // 在实际开发中,真正代码时间可能只占20-30% ,其他时间都在理解需求,想思路 importjava.net.URL importorg.apache.spark.{SparkConf,SparkContext} objectData_anlysis{ defmain(args:Array[String]){ valconf=newSparkConf().setAppName("data-anysis").setMaster("local[2]") valsc=newSparkContext(conf) vallinesRDD=sc.textFile("d://web_data.log") valrdd01=linesRDD.map(line=>{ vallineSplited=line.split("\t") (lineSplited(1),1) }) valrdd02=rdd01.reduceByKey(_+_) valrdd03=rdd02.map(tup=>{ valurl=tup._1; valhost=newURL(url).getHost (host,url,tup._2) }) valrdd04=rdd03.groupBy(_._1) valrdd05=rdd04.mapValues(iter=>{ iter.toList.sortBy(_._3).reverse.take(2) }) println(rdd05.collect().toBuffer) sc.stop() } } 运行结果会把网站的日志数据按照某一模块的要求列出排名前2个结果展示出来。 本文转自 ChinaUnicom110 51CTO博客,原文链接:http://blog.51cto.com/xingyue2011/1950745

优秀的个人博客,低调大师

[Android Pro] Scroller使用分析

reference to :http://blog.csdn.net/a910626/article/details/51548840 一.Scroller是什么? Android里 Scroller类是为了实现View平滑滚动的一个Helper类。通常在自定义的View时使用,在View中定义一个私有成员mScroller = new Scroller(context)。设置mScroller滚动的位置时,并不会导致View的滚动,通常是用mScroller记录/计算View滚 动的位置,再重写View的computeScroll(),完成实际的滚动。 Scroller只是个计算器,提供插值计算,让滚动过程具有动画属性,但它并不是UI,也不是辅助UI滑动,反而是单纯地为滑动提供计算。 无论从构造方法还是其他方法,以及Scroller的属性可知,其并不会持有View,辅助ViewGroup滑动。 Scroller只是提供计算,那谁来调用computeScroll使得ViewGroup滑动 computeScroll也不是来让ViewGroup滑动的,真正让ViewGroup滑动的是scrollTo,scrollBy。computeScroll的作用是计算ViewGroup如何滑动。而computeScroll是通过draw来调用的。 computeScroll和Scroller都是计算,两者有啥关系?没有直接的关系。computeScroll和Scroller要 是飞得拉关系的话,那就是computeScroll可以参考Scroller计算结果来影响scrollTo,scrollBy,从而使得滑动发生改 变。也就是Scroller不会调用computeScroll,反而是computeScroll调用Scroller。 滑动时连续的,如何让Scroller的计算也是连续的?这个就问到了什么时候调用computeScroll了,如上所说 computeScroll调用Scroller,只要computeScroll调用连续,Scroller也会连续,实质上 computeScroll的连续性又invalidate方法控制,scrollTo,scrollBy都会调用invalidate,而 invalidate回去触发draw,从而computeScroll被连续调用,综上,Scroller也会被连续调用,除非invalidate停 止调用。 computeScroll如何和Scroller的调用过程保持一致?computeScroll参考Scroller影响 scrollTo,scrollBy,实质上,为了不重复影响scrollTo,scrollBy,那么Scroller必须终止计算 currX,currY。要知道计算有没有终止,需要通过mScroller.computeScrollOffset() 二.这个知识应用场景是?可以解决什么问题? 我们在需求实现时,经常遇到view滑动的情况,而scrollTo、scrollBy方法都可以实现view的滑动,但是效果是瞬间完成的, 用户体验并不好,我们可以使用scroller或者smoothScrollto(内部也是scroller实现的)来实现平滑移动的效果。常见于自定义 view中。 三.该类的常见API? mScroller.getCurrX() //获取mScroller当前水平滚动的位置 mScroller.getCurrY() //获取mScroller当前竖直滚动的位置 mScroller.getFinalX() //获取mScroller最终停止的水平位置 mScroller.getFinalY() //获取mScroller最终停止的竖直位置 mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置 mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置 //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间 mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms mScroller.startScroll(int startX, int startY, int dx, int dy, int duration) mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。 四.常规的用法是什么? Scroller的基本用法其实还是比较简单的,主要可以分为以下几个步骤: 1. 创建Scroller的实例 2. 调用startScroll()方法来初始化滚动数据并刷新界面 3. 重写computeScroll()方法,并在其内部完成平滑滚动的逻辑 五.使用时的难点在哪里? 使用的难点在于startScroll的参数含义,然后根据参数含义给出合适的值,因为这个过程涉及android中坐标计算,所以较为复杂。 // void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration) // 第一个参数是起始移动的x坐标值, // 第二个是起始移动的y坐标值, // 第三个第四个参数都是移到某点的坐标值-初始的坐标值,即移动的距离值 // 而duration 当然就是执行移动的时间。 六.一个案例:来自《android群英传》 public class ScrollerDragView extends View { private Scroller mScroller; private int mLastX; private int mLastY; public ScrollerDragView(Context context) { super(context); initView(context); } public ScrollerDragView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context) { setBackgroundColor(Color.BLUE); mScroller = new Scroller(context); } @Override public boolean onTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mLastX = (int) event.getX(); mLastY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; // 貌似使用了getParent,就不再需要重置x,y的坐标了 ((View)getParent()).scrollBy(-offsetX, -offsetY); break; case MotionEvent.ACTION_UP: View viewGroup = (View) getParent(); mScroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY()); invalidate(); break; } return true; } /** * 这里不需要特别的理解,只要使用Scroller,这里都是一样的 */ @Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { ((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } } } 分类: Android Pro 本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/p/6113099.html如需转载请自行联系原作者 demoblog

优秀的个人博客,低调大师

koa-router源码分析

koa-router源码地址是 koa-router 当前解读版本为7.2.1 关系图 代码结构图执行流程图关系对应图 Router方法和属性浅析 methods.forEach 注册注册路由的方法,结果就是Router的原型上面多了get,post,delete,del等注册路由的方法 代码使用的时候 r1.get就是这么来的 r1.get('/test1/:id', function (ctx, next) { console.log('test1 :1') next() }, function (ctx, next) { console.log('test1:2') }) Router.prototype.del 等同于 Router.prototype.delete Router.prototype.use 注册中间件,支持形式多种多样 看着这么多,其实就两种中间件, 普通中间件 router.routes()返回的中间件 重点就是router.routes()返回的这种件,需要的前缀,参数验中间件做一些处理 router.use(function (ctx, next) { ctx.foo = 'baz'; return next(); }); router.use('/foo/bar', function (ctx, next) { ctx.foo = 'foo'; return next(); }); router.use('/foo', subrouter.routes()); router.use(['/foo', '/bar'], function (ctx, next) { ctx.foo = 'foo'; ctx.bar = 'bar'; return next(); }); parentRouter.use('/parent-route', function (ctx, next) { ctx.n = ctx.n ? (ctx.n + 1) : 1; return next(); }, nestedRouter.routes()); Router.prototype.prefix 给router实例添加前缀,前缀可以是包含参数的 router.prefix('/things/:thing_id') Router.prototype.routes = Router.prototype.middleware 返回中间件, 中间执行的时候,会根据path获取满足匹配条件的路由(Layer),然后根据每个Layer生成一个解析参数值的中间,这就是为什么我们在ctx.params能得到参数值 最核心的代码如下 layerChain = matchedLayers.reduce(function(memo, layer) { memo.push(function(ctx, next) { ctx.captures = layer.captures(path, ctx.captures); ctx.params = layer.params(path, ctx.captures, ctx.params); return next(); }); return memo.concat(layer.stack); }, []); return compose(layerChain)(ctx, next); matchedLayers是匹配的Layer或者说一条路由信息,同一个路径同样的方法也是会生成两条记录的,如下同样的注册,会生成两个不同路由(Layer),哪怕信息一模一样 r1.get('/test1', function (ctx, next) { console.log('test1 :1') next() }) r1.get('/test1', function (ctx, next) { console.log('test1 :2') next() }) matchedLayers.reduce没执行一次,是生成两个中间件, 一个是参数解析的中间件,这就是为什么你可以通过ctx.params取值到路由参数了 function(ctx, next) { ctx.captures = layer.captures(path, ctx.captures); ctx.params = layer.params(path, ctx.captures, ctx.params); return next(); } 另外一个才是实际路由匹配的执行方法,上面的demo就是 function (ctx, next) { console.log('test1 :1') next() } Router.prototype.allowedMethods 此方法执行很靠后,在他后面注册的中间件执行完毕后才执行 生成一个中间件,作用是定义路由没匹配到,方法未允许,方法未实现等的返回信息 app.use(router.routes()); app.use(router.allowedMethods({ throw: true, notImplemented: () => new Boom.notImplemented(), methodNotAllowed: () => new Boom.methodNotAllowed() })); Router.prototype.all 注册一个路由,允许所有的get,post等方法访问 Router.prototype.redirect 跳转,原理就是注册了一个路由,用ctx.redirect来实现跳转 router.redirect('/login', 'sign-in'); 等同于 router.all('/login', function (ctx) { ctx.redirect('/sign-in'); ctx.status = 301; }); Router.prototype.register 核心方法之一,注册中间件 Router.prototype.all,methods.forEach等底层都是调用这个家伙实现的 Router.prototype.use也依据情况会调用 Router.prototype.route 查找具名的route(Layer) Router.prototype.url 生成url,可以传参 router.get('user', '/users/:id', function (ctx, next) { // ... }); router.url('user', 3); // => "/users/3" router.url('user', { id: 3 }); // => "/users/3" router.use(function (ctx, next) { // redirect to named route ctx.redirect(ctx.router.url('sign-in')); }) Router.prototype.match 获得匹配的路由(Layer),以path和method来过滤的 router.routes返回的中间件底层就是通过他来确认请求应该进入哪些路由的 Router.prototype.param 添加参数验证中间件,这个需要结合Layer.prototype.param 一起来理解 Router.prototype.param = function (param, middleware) { this.params[param] = middleware; this.stack.forEach(function (route) { route.param(param, middleware); }); return this; }; Layer.prototype.param = function (param, fn) { var stack = this.stack; var params = this.paramNames; // 构建参数验证中间件 var middleware = function (ctx, next) { return fn.call(this, ctx.params[param], ctx, next); }; middleware.param = param; var names = params.map(function (p) { return p.name; }); var x = names.indexOf(param); if (x > -1) { // iterate through the stack, to figure out where to place the handler fn stack.some(function (fn, i) { // param handlers are always first, so when we find an fn w/o a param property, stop here // if the param handler at this part of the stack comes after the one we are adding, stop here // fn.param 作为判断是不是参数验证中间件的标志 // 如果不是参数验证中间件,或者参数验证中间件需要验证的参数在我之后,插入参数验证中间件 // 比如说path是这样的 /user/:id/posts/:postid, 那么id参数验证中间件应该在postid参数之前 // 简单说,确保参数按照顺序被验证 if (!fn.param || names.indexOf(fn.param) > x) { // inject this param handler right before the current item stack.splice(i, 0, middleware); return true; // then break the loop } }); } return this; }; Layer方法和属性浅析 Layer.prototype.match path是否匹配路由 Layer.prototype.params 获得路由参数键值对 Layer.prototype.captures 获得路由参数的值 Layer.prototype.url 用参数构建URL,params参数可视是对象也可是数组 Layer.prototype.param 添加参数验证中间件 Layer.prototype.setPrefix 设置前缀 safeDecodeURIComponent decodeURIComponent错误时返回原值 更多细节请直接看带备注的源码吧,写东西真累啊!RouterLayer koa-router 源码解析 - segmentfault解析Koa-Router,迈入Web次时代第一步(上)Koa-Router 源码解析下 -CNodekoa-router源码解读 Koa-router 优先级问题 Path-to-RegExp 使用

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册