花花你为什么不叫海鲜 发布于 01月22, 2017

浅谈用户登录

有一天火麒麟后台忽然不好使了,由于公司内网对阿里云的IP没办法访问,所以没办法,我回家登上数据库,发现动态的修改的密码,也是不能登陆的。。。于是就登陆的这一逻辑追查了下去,当然最后问题肯定是解决了,在这里分享给大家。

阅读全文 »

花花你为什么不叫海鲜 发布于 01月11, 2017

【译】10倍提升应用性能的10个建议

原文:http://www.zcfy.cc/article/22

提升Web应用的性能从未像今天这样刻不容缓。在线经济活动的比例日益提高,就连发展中国家和地区的经济活动都已经有5%以上在线进行了(相关数据请参考本文后面的资源)。在这个超级链接、随时在线的现代世界,用户的期望也远非昔日可比。如果你的网站不能马上响应,你的应用不能立即运行,用户转身就会投奔你的竞争对手。

阅读全文 »

花花你为什么不叫海鲜 发布于 01月09, 2017

【译】性能日志 » 使用HTTP2和渐进式JPEG图片更快的加载图像

原文链接:Performance Calendar » Even Faster Images using HTTP2 and Progressive JPEGs

众城平台翻译链接:性能日志 » 使用HTTP2和渐进式JPEG图片更快的加载图像 (感谢月影大大推荐文章)

tl;dr: 渐进式图像在HTTP 2上渲染得更快,从而增加感知性能。控制渐进JPEG扫描图层来实现只用25%的图像数据展示具有核心意义的图像内容。对于渐进式JPEG使用HTTP Server Push,来最大化关键图像的渲染性能。

阅读全文 »

花花你为什么不叫海鲜 发布于 12月21, 2016

【译】多进程架构

题目:多进程架构

原文链接:Multi-process Architecture

不像大多数web浏览器,谷歌浏览器使用了许多操作系统进程来保持各个网站相互分离和计算机的其余部分的分离。通过这篇博客,我将告诉你,在当今的网站,为什么使用混合架构体统会是一个巨大的成功。同时,我也会谈到,浏览器的哪一部分数据哪个进程,在什么情况下浏览器会创建新的进程。

1.为什么在浏览器中使用多进程

当大多数现在的浏览器被设计出来的时候,有那么一段时间,网页是很简单的,有极少的代码或者说干脆就没有代码。那么浏览器渲染在同一个进程中去渲染你所有浏览网页,以保持资源的低利用率就很合理了。

但是,现如今,我们可以看到主要转向活跃的网页内容,从拥有大量JS和Flash的网页到完整的“网络应用app”,比如:Gmail。大量的app都是内嵌浏览器,就像普通的应用跑在一个操作系统上。正如一个操作系统,浏览器必须保证这些应用程序是彼此分离的。

阅读全文 »

花花你为什么不叫海鲜 发布于 12月12, 2016

Linux使用配置

alias使用笔记

alias设置指令的别名。

语法:

#  alias name='command line'

参数:

-p: 打印出现有的别名(唯一的参数)

若不加任何参数,则列出目前所有的别名设置

永久设置:

vim ~/.bash_profile 进行编辑

格式:

alias name='command line'

注意中间没有空格!

eg.

alias newhouse='cd /data0/www/htdocs/'

修改后执行:

source .bash_profile 重新执行文件

阅读全文 »

花花你为什么不叫海鲜 发布于 12月08, 2016

【 译】Page Visibility API

当一个网站是可见或点击选中的状态时 Page Visibility API 可以让你获取到这种状态。 在用户使用切换标签的方式来浏览网页时,非常合理的情况是任何在后台页面都不会展示给用户。 当用户最小化网页或者浏览到其他标签的网页时,API将发送一个关于当前页面的可见信息的事件{{event("visibilitychange")}} 。你可以检测该事件然后执行一些活动或是展示不同的效果。比如,如果你的网站app正在播放一个视频,也许当用户浏览其他浏览器时它可以暂停,那么当用户切换回来的时候,就可以继续播放了。用户可以继续观看,不会因为浏览其他的浏览器导致丢失当前视频的进度。

关于iframe的可见性的状态等同于它的父层iframe。用CSS属性隐藏iframe并不会触发visibility事件也不会改变内容文本的状态。 好处

这个API在节约资源上是非常有用的,当网页不可见时,这个API通过提供给开发者可以操作不必须的任务的接口。

使用情景

一些例子:

  • 网站有图片轮播效果,只有在用户观看轮播的时候,才会自动展示下一张幻灯片。
  • 显示信息仪表盘的应用程序不希望在页面不可见时轮询服务器进行更新。
  • 页面想要检测是否正在渲染,以便可以准确的计算网页浏览量
  • 当设备进入待机模式时,网站想要关闭设备声音(用户按下电源键关闭屏幕) 开发者在过去使用不完善的代理来处理这一点。比如, 当你的页面不处于活动状态时,在window上声明一个 onblur/onfocus 处理器来帮助你了解页面不是活动状态,但是它并没有告诉你页面是对用户隐藏的。The Page Visibility API 解决了这个问题。(在和window上声明 onblur/onfocus 处理器这种方式相比,关键不同在于当另一个页面处于激活状态并且浏览器窗口丢失了焦点时,页面不会隐藏。 页面只有在用户切换到其他标签或最小化窗口时,才会被隐藏。)

例子

看一个 在线的例子 (带声音的视频) 在此例中,当你切换到另一个标签时视频会暂停,当你返回到当前标签时视频会再次播放,代码如下:

// 设置隐藏属性和改变可见属性的事件的名称
var hidden, visibilityChange; 
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support 
  hidden = "hidden";
  visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
  hidden = "msHidden";
  visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
  hidden = "webkitHidden";
  visibilityChange = "webkitvisibilitychange";
}

var videoElement = document.getElementById("videoElement");

// 如果页面是隐藏状态,则暂停视频
// 如果页面是展示状态,则播放视频
function handleVisibilityChange() {
  if (document[hidden]) {
    videoElement.pause();
  } else {
    videoElement.play();
  }
}

// 如果浏览器不支持addEventListener 或 Page Visibility API 给出警告
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
  console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
  // 处理页面可见属性的改变
  document.addEventListener(visibilityChange, handleVisibilityChange, false);

  // 当视频暂停,设置title
  // This shows the paused
  videoElement.addEventListener("pause", function(){
    document.title = "Paused";
  }, false);

  // 当视频播放,设置title
  videoElement.addEventListener("play", function(){
    document.title = "Playing"; 
  }, false);

}

属性

document.hidden Read only

如果页面处于被用户认为是隐藏状态时返回true,否则返回false。

document.visibilityState Read only

是一个用来展示文档可见性状态的字符串。可能的值:

  • visible : 页面内容至少是部分可见。 在实际中,这意味着页面时非最小化窗口的前景选项卡。
  • hidden : 页面内容对用户不可见。 在实际中,这意味着文档可以是一个后台标签,或是最小化窗口的一部分,或是在操作系统锁屏激活的状态下。
  • prerender : 页面内容正在被预渲染且没有对用户是不可见的(被当做隐藏,以 document.hidden 为目的 ). 文档可能初始状态为prerender,但绝不会从其它值转为该值。 注释:浏览器支持是可选的。
  • unloaded : 页面正在从内存中卸载。 注释:浏览器支持是可选的。
//startSimulation 和 pauseSimulation 在其他地方定义
function handleVisibilityChange() {
  if (document.hidden) {
    pauseSimulation();
  } else  {
    startSimulation();
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

附:

MDN翻译链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Page_Visibility_API

MDN英文文档链接:https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

阅读全文 »

花花你为什么不叫海鲜 发布于 11月24, 2016

Linux中软链接与硬链接

Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link)。默认情况下,ln命令产生硬链接。

#Hard Link: 在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。 硬连接的2个限制: l 不允许给目录创建硬链接 l 只有在同一文件系统中的文件之间才能创建链接。 即不同硬盘分区上的两个文件之间不能够建立硬链接。这是因为硬链接是通过结> 点指向原始文件的,而文件的i-结点在不同的文件系统中可能会不同。

#Symbolic Link: 软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

使用:

Hard Link: ln [源文件] [目标文件]

Symbolic Link: ln -s [源文件] [目标文件]

查看: ls -l

举个栗子: 建立单个文件的软链接: 建立文件夹的软链接,注意源文件的目录为文件夹中的内容,所以此处用: [源文件夹]/。目标文件的目录为正常路径。 我创建了link1作为源文件,linkHard作为硬链接文件,linkSymbolic作为软链接文件 编辑link1后,两个文件都同步更新了,当删除link1时,软链接会自动失效

综上:

  1. 删除源文件->软链接失效文件被删除,硬链接依然存在
  2. 删除硬链接 -> 删除源文件且删除硬链接文件
  3. 删除软链接,使用rm

摘录自:http://www.cnblogs.com/sonic4x/archive/2011/08/05/2128543.html

阅读全文 »

花花你为什么不叫海鲜 发布于 11月21, 2016

国内npm镜像推荐

淘宝npm镜像

搜索地址:http://npm.taobao.org/ registry地址:http://registry.npm.taobao.org/

cnpmjs镜像

搜索地址:http://cnpmjs.org/ registry地址:http://r.cnpmjs.org/

使用方式:

1.一次性

npm --registry https://registry.npm.taobao.org install express

2.长期设置

npm config set registry https://registry.npm.taobao.org

// 配置后可通过下面方式来验证是否成功
npm config get registry
// 或
npm info express

3.通过cnpm使用

npm install -g cnpm --registry=https://registry.npm.taobao.org

// 使用
cnpm install express

4.通过qnpm使用

npm install -g @q/qnpm --registry=http://registry.npm.qiwoo.org

// 使用
cnpm install express

附:相关文档http://qnpm.qiwoo.org/

阅读全文 »

花花你为什么不叫海鲜 发布于 08月21, 2016

Thinkjs实现异步加载

今天来总结一下关于使用Thinkjs来实现页面异步加载的原理和做法。 我从前端讲起,首先流程中包含一下几部分:

View Controller Model
筛选框(filter)用于筛选内容,位置在母模版 母模版对应的Action 调用数据库
异步加载内容(content),位置在子模板 ajax判断后的处理 调用数据库

下面根据代码具体解释一下: 母模版的view层demo:

/*这里是一个filter*/
<div class="filter">
    <dl class="row">
        <dt>大小</dt>
        <dd>
            <a href="#">全部</a>
            <a href="#"></a>
            <a href="#"></a>
            <a href="#"></a>
        </dd>
    </dl>
</div>
/*这里是一个content*/
<div class="content">
    <%include ajax/tplselectajax.html%>     /*这里include进来一个子模板,将来异步刷新时就只刷新子模板数据*/
</div>

子模板的view层demo: 可以看到从后端传来一个tpllist的数据字段,相当于是一个数组,我们把它循环输出出来,同时一会异步刷新的时候我们也只是刷新这个子模板的数据,而不会改变上面的母模板的数据。

<div class="cont-wrap">
    <ul>
        <%tpllist.forEach(function(item){ %>
            <li>
                <p><%=item.desc%></p>
                <p><%=item.name%></p>
            </li>
        <%})%>
    </ul>
</div>

当然这里需要js来帮忙使用ajax来进行一步调用:

$("a").on("click",function(e){
    e.preventDefault();
    $.ajax({
        url:"",/*填写请求路径*/
        dataTpe:"jsonp",
        data:"",/*传送的数据*/
        success:function(){

        },
        fail:function(){

        }

    });
});

Controller层的处理:

tplselectAction: function(){
    var self = this;
    /*获取get请求的参数,在这个demo中其实就是筛选条件*/
    var data = this.get();  
    var pg = data.pg;
    /*判断时候是ajax请求,如果是则结果返回true*/
    var isAjax = self.isAjax();   
    /*子模板渲染路径,注意此处根目录是Home*/
    var tpl = "Home/ajax/build_tplselectajax.html";         
    if(!isAjax){
        /*如果不是ajax请求,也就是浏览器首次渲染数据时,默认选择展示全部数据*/
        data = { cateId: "全部"}
    }
    /*调用数据库获取数据,调用ajaxdata方法*/
    D("Template").ajaxdata(data,pg).then(function(data){
        var list = shiftObject(data,"data");  /*将数据库data字段整体存入list*/
        self.assign("tpllist",list);  
        self.assign("isAjax",isAjax);
        if(isAjax){
            /*如果是ajax模板,则利用fetch这个方法对模板进行重新渲染,并返回相应json格式的状态值*/
            if(list.length !== 0){
                self.fetch(tpl).then(function(content){
                   self.jsonp({status:"success",cont:content});
                });
            }else{
                self.jsonp({status:"fail",cont:"暂时木有相应的模板,搜搜别的试试吧!"});
            }
        }else{
            /*首次加载页面则直接展示*/
            self.display();
        }
    });
}

Model层的处理demo:

ajaxdata: function(data){
    var self = this;
    if(data.cateId = "全部"){
        return self.order({"id":"desc"}).select().then(function(data){
            return data;
        });
    }else{
        return self.where({"title":data.cateId}).order({"id":"desc"}).select().then(function(data){
            return data;    
        });
    }
}

Model层的处理: 这里是项目源代码的查询:

ajaxdata: function(data,pg){
        var self = this;
        var where = where || {};
        /*此处包含其他参数的复合查询,展示出来,在demo中暂时不考虑*/
        /*var join = {
            templatecate: {
                join: "left",
                as: "c",
                on: ["cateId","id"]
            }
        };
        var pg = pg || (isNumber(where) ? where : null);
        var lastCond = {};
        if(!isEmpty(where)){
            for(var i in where){
                var find = false;
                for(var s in fields){
                    if(fields[s].indexOf(i) > -1){
                        lastCond[s + "." + i] = where[i];
                        find = true;
                        break;
                    }
                }
                if(find)continue;
                lastCond["t." + i] = where[i];
            }
        }*/
        if(data.cateId == "全部"){
            var per = C("db_nums_per_page");
            /*在筛选框为‘全部’时,将数据中全部数据按条件查询出来,并且进行分页查询(分页查询此处我们暂时不讨论)*/
            return self.where({"endType":data.endType,"isForbidden":0}).order({"id": "desc"}).page(pg).select().then(function(data){
                    return data;
            }).then(function(datalist){
                /*将返回结果进行处理,并返回相应的参数*/
                return self.field("count(id) as count").where({"endType":data.endType}).find().then(function(res){
                    return {
                        data: datalist,
                        count: res.count,
                        page: pg || 1,
                        num: per,
                        total: Math.ceil(res.count / per)
                    };
                });
            }); 
        }else{
            /ajax请求是查询结果,按照cateId的值进行查询/
            var per = C("db_nums_per_page");
            return self.alias("t").field("t.*").join(join).where({"c.title":data.cateId,"t.endType":data.endType,"isForbidden":0}).order({"t.id": "desc"}).page(pg).select().then(function(data){
                    return data;
            }).then(function(datalist){
                return self.alias("t").field("count(t.id) as count").join(join).where({"c.title":data.cateId,"t.endType":data.endType}).find().then(function(res){
                    return {
                        data: datalist,
                        count: res.count,
                        page: pg || 1,
                        num: per,
                        total: Math.ceil(res.count / per)
                    };
                });
            }); 
        }

    }

关于Thinkjs里面的具体语法我就不一一解释了,这里主要来讲一下大概的思路,首先前端需要在模板中将需要异步加载的模板进行include,方便后续的异步刷洗页面,同时你需要用js来进行一个ajax的通信,接着就是Controller层对模板的渲染,在拿到前端传来的请求数据后,调用model层的方法从数据库中取出数据,此时需要使用feteh这个方法重新渲染页面。(其实也可以使用display(渲染模板路径)这个方法,只是渲染的方式不用而已,结果是一样的)感兴趣的同学可以搜一下API。 sql语句写的不好,还望大家见谅~~哈哈哈,先就这么多~

阅读全文 »

花花你为什么不叫海鲜 发布于 08月21, 2016

HTTP解读(二)

title: HTTP解读(二) date: 2016-02-05 11:07:42

tags:

这篇文章我们来结合上一篇HTTP解读(一)唆唆HTTP中一些基本的概念,主要也是我想归纳一下一些基本的知识点。 上篇中提到了客户端发送了一条请求后是经历了怎样的层层关卡才到达了服务器,我们这里就每一层的细节展开分析。 HTTP报文是简单的格式化数据块,分为:请求报文和响应报文,由三部分组成:起始行(start line) 首部(header) 主体(body) 报文包含:方法(method)请求URL(request-URL)版本(version)状态码(status-code)原因状态(reason-phrase)首部(header)实体的主体部分(entity-body) 一。起始行(所有HTTP报文都包含起始行):包含请求行和响应行两部分 1.请求行

  • 请求报文的起始行说明要做什么,响应报文的起始行说明发生了什么。
  • 包含:一个方法+一个请求URL
  • 方法描述服务器应该执行的操作,请求URL描述对哪个资源执行这个方法
  • 请求行中包含HTTP版本,告诉服务器使用哪个HTTP方案

2.响应行

  • 包含响应报文HTTP版本,数字状态码,描述操作状态的文本形式的原因短语

3.方法 总体来说,客户端向服务器发送请求无外乎以下几种标准方法(注意这里只是说标准方法,包含不仅限于这几种,有的服务器还是实现了自己特有的HTTP的方法,称为扩展方法):

方法 描述 是否包含主体
GET 从服务器获取一份文档
HEAD 只从服务器获取响应报文的头部
POST 向服务器发送需要处理的数据
PUT 将请求的主体部分存储在服务器上
TRACE 对可能经过代理服务器传送到服务器上的报文进行追踪
OPTIONS 决定在服务器上可以执行哪些方法
DELETE 从服务器上删除一份文档

4.状态码 方法是用来告诉服务器做什么事情,状态码是用来告诉客户端发生了什么事情,状体码分为以下几类:

整体范围 已定义范围 分类
100~199 100~101 信息提示
200~299 200~206 成功
300~399 300~305 重定向
400~499 400~415 客户端错误
500~599 500~505 服务器错误

常见的状态码: 200 状态短语:OK 成功,401 状态短语:Unauthorized(未授权) 需要输入用户名和密码,404 状态短语:Not Found 未找到,502 状态短语:Bad Category 网关错误

5.原因短语

6.版本号 HTTP/x.y形式出现 二。首部:包含通用首部,请求首部,响应首部,实体首部,扩展首部 常见首部:如图 alt

通用首部中还包含通用缓存首部,请求首部中包含Accept首部,条件请求首部,安全请求首部,代理请求首部。 响应首部中包含协商首部,安全响应首部。 实体首部中包含内容首部,实体缓存首部。 三。主体:HTTP报文实体主体部分是可选的 说了这么多是不是很不直观?没关系,来举个🌰就直观了。比如:我现在在浏览器地址栏中输入了:http:www.imwineki.cn/index.html,当我按下回车后的下一秒,浏览器就向服务器发送了一条get请求,请求的文档的当然就是index.html这个文件了,当然服务器会将文件找到后返回回来,酱紫你就能看到我的博客的主页了(通常相应的状态是200)。这张图就是我发送请求是的截图,我们来分析一下: alt

起始行信息: Request Url跳转链接,Request Method请求方法为get方法,Remote status相应状态码200 ok,Remote Address请求IP地址(默认80端口) 首部:Request Header 通用首部:Date:Fri, 05 Feb 2016 10:44:59 GMT Connection:keep-alive Via:1.1 varnish 通用缓存首部:Cache-Control:max-age=600 请求首部:Accept-Ranges:bytes Host:imwineki.cn User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36 响应首部:Server:GitHub.com 实体首部:Content-Encoding:gzip Content-Length:4838 Content-Type:text/html; charset=utf-8 差不多就这些了,写的好辛苦@……@!

阅读全文 »