[转载]大流量网站性能优化:一步一步打造一个适合自己的BigRender插件 - 韩子迟 - 博客园

mikel阅读(1836)

来源: [转载]大流量网站性能优化:一步一步打造一个适合自己的BigRender插件 – 韩子迟 – 博客园

当一个网站越来越庞大,加载速度越来越慢的时候,开发者们不得不对其进行优化,谁愿意访问一个需要等待 10 秒,20 秒才能出现的网页呢?

常见的也是相对简单易行的一个优化方案是 图片的延迟加载。 一个庞大的页面,有时我们并不会滚动去看下面的内容,这样就浪费了非首屏部分的渲染,而这些无用的渲染,不仅包括图片,还包括其他的 DOM 元素,甚至一些 js/css(某些js/css 是根据模块请求的,比如一些 ajax),理论上,每增加一个 DOM,都会增加渲染的时间。有没有办法能使得 HTML、js、css 都能按需加载呢?答案是肯定的,这就是本文要讲的 BigRender。

业界有很多 BigRender 在生产环境中的案例,比如 新浪美团途牛旅行网360网址导航淘宝商品详情页 等等。查看它们的源代码(ctrl+u),ctrl+f 搜索 textarea 关键字,很容易可以看到一些被 textarea 标签包裹的 HTML 代码。

比如途牛:

而这些被 textarea 标签包裹的 HTML 代码,只是 textarea 的 value 值,并没有渲染到 DOM 树上。没错,BigRender 通常就是用 textarea 标签包裹 HTML 代码(js/css),当作其 value 值,等到合适的时机(通常当 textarea 标签出现或者即将出现在用户视野时)将 textarea 中的 HTML 代码取出,用 innerHTML 动态插入到 DOM 树中,如有必要,取出 js/css 代码(正则),动态执行它们。(是不是和图片的延迟加载很相似?)

玉伯指出

页面下载完毕后,要经过 Tokenization — Tree Construction — Rendering. 要让首屏尽快出来,得给浏览器减轻渲染首屏的工作量。可以从两方面入手:

  1. 减少 DOM 节点数。节点数越少,意味着 Tokenization, Rendering 等操作耗费的时间越少。(对于典型的淘宝商品详情页,经测试发现,每增加一个 DOM 节点,会导致首屏渲染时间延迟约 0.5ms.)

  2. 减少脚本执行时间。脚本执行和 UI Update 共享一个 thread, 脚本耗的时间越少,UI Update 就能越发提前。

为什么是用 textarea 标签存放大块 HTML 内容?还是可以看下玉伯的 这篇文章。淘宝的 kissy 就内置了 DataLazyload 组件。(插播:美团详情页还有用到 script 标签做 BigRender 优化,详情请见下面的 “其他” 一节)

接下去就来一步一步实现一个适合自己的 BigRender 插件,我希望可以延迟加载 HTML 元素、js 以及 css。

T.datalazyload

仿照 JQuery 的写法我定义了一个全局对象 T,将延迟加载的实现代码封装在了 T.datalazyload 对象中,将需要延迟加载的代码 “包裹” 在 textarea 标签中,设置其 visibility 属性为 hidden,并赋予该标签一个特殊的类名(为了做事件监听),比如叫做 “datalazyload”。为了方便,我规定每个做 bigrender 优化的 textarea 的父节点都只有一个子孩子(即该 textarea 元素),这一点非常重要必须遵守,因为后面代码有针对此的特殊处理。(注意要设置好父节点的高度宽度,和 dom 渲染后的高度宽度保持一致)

一些 HTML/js/css 代码都可以包裹在 textarea 标签中,例如:

<textarea class="datalazyload" style="visibility: hidden;"> 
  <script type="text/javascript">
    alert("I am lazyload zone!"); 
  </script>

  <style type="text/css">
    .main {margin: 0 auto; text-align: center; padding-top: 200px; width:1000px; height:1000px; border:5px black dashed;}
    .second {margin: 0 auto; width:1000px; height:200px; border: 5px purple dotted; padding-top: 100px; text-align: center;}
  </style>
  <div class="second">
    <h1>我是延迟加载的部分!</h1>
  </div>
</textarea>

init

给 T.datalazyload 对象定义一个 init() 方法,初始化页面时监听 scroll、resize 以及移动端的 touchmove 事件,当触发这些事件时,回调函数内判断延迟加载部分是否已经出现在视口。

init: function(config) {
  var cls = config.cls;
  this.threshold = config.threshold ? config.threshold : 0;

  this.els = Array.prototype.slice.call(T.getElementsByClassName(cls));
  this.fn = this.pollTextareas.bind(this);

  this.fn();
  T.addEvent(window, "scroll", this.fn);
  T.addEvent(window, "resize", this.fn);
  T.addEvent(doc.body, "touchMove", this.fn);
}

config 是配置参数,其 cls 属性表示需要延迟加载的 textarea 的类名,threshold 为阈值,单位 px,表示当 textarea 距离视口多少像素时,进行预加载。

将需要延迟加载的元素存入一个数组(this.els),(某 textarea 元素)后续一旦完成加载随即在数组中删除该元素。事件监听的回调函数为 pollTextarea() 方法。

pollTextarea

pollTextareas: function() {

  // 需延迟加载的元素已经全部加载完
  if (!this.els.length) {
    T.removeEvent(window, "scroll", this.fn);
    T.removeEvent(window, "resize", this.fn);
    T.removeEvent(doc.body, "touchMove", this.fn);
    return;
  }

  // 判断是否需要加载
  for (var i = this.els.length; i--; ) {
    var ele = this.els[i];

    if (!this.inView(ele)) 
      continue;

    this.insert(ele);
    this.els.splice(i, 1);
  }
}

这个方法的作用是判断需要延迟加载的元素是否已经在视口,如果是,则进行加载(触发 insert 方法),并且在数组中删除该元素;如果数组为空,则表明需要延迟加载的部分都已经加载完,移除事件监听,整个延迟加载结束。

insert

接下去看 insert 方法。inert 方法的参数是需要延迟加载的 textarea 元素,很显然,我们需要解析的代码全在 textarea.innerHTML 中。我们用 extractCode 方法取出其中的 js/css 代码,然后将 js/css 过滤掉,这样剩下的就全是 HTML 代码了,将其插入 DOM 中(这正是前文说的 “每个 textarea 的父节点都只有一个子孩子” 的原因,可以直接用父节点 innerHTML 操作),如果有 loading 效果,一般在父节点加个 loading 类,移除即可。最后再动态执行 js 脚本,插入 css 样式。

insert: function(ele) {
  var parent = ele.parentNode
    , txt = this.decodeHTML(ele.innerHTML)
    , matchStyles = this.extractCode(txt, true)
    , matchScripts = this.extractCode(txt);

  parent.innerHTML = txt
    .replace(new RegExp("<script[^>]*>([\\S\\s]*?)</script\\s*>", "img"), "")
    .replace(new RegExp("<style[^>]*>([\\S\\s]*?)</style\\s*>", "img"), "");

  if (matchStyles.length) 
    for (var i = matchStyles.length; i --;) 
      this.evalStyles(matchStyles[i]);

  // 如果延迟部分需要做 loading 效果
  parent.className = parent.className.replace("loading", "");

  if (matchScripts.length) 
    for (var i = 0, len = matchScripts.length; i < len; i++) 
      this.evalScripts(matchScripts[i]);
},

extractCode

我们通过正则将 js 和 css 标签部分取出:

extractCode: function(str, isStyle) {
  var cata = isStyle ? "style" : "script"
    , scriptFragment = "<" + cata + "[^>]*>([\\S\\s]*?)</" + cata + "\\s*>"
    , matchAll = new RegExp(scriptFragment, "img")
    , matchOne = new RegExp(scriptFragment, "im")
    , matchResults = str.match(matchAll) || [] 
    , ret = [];

  for (var i = 0, len = matchResults.length; i < len; i++) {
    var temp = (matchResults[i].match(matchOne) || [ "", "" ])[1];
    temp && ret.push(temp);
  }
  return ret;
}

成功地将 script 以及 style 标签内的内容提取了出来,巧妙地用了正则中的子表达式。

evalScripts/evalStyles

脚本执行,样式渲染。

evalScripts: function(code) {
  var head = doc.getElementsByTagName("head")[0]
    , js = doc.createElement("script");

  js.text = code;
  head.insertBefore(js, head.firstChild);
  head.removeChild(js);
},

evalStyles: function(code) {
  var head = doc.getElementsByTagName("head")[0]
    , css = doc.createElement("style");

  css.type = "text/css";
  try {
    css.appendChild(doc.createTextNode(code));
  } catch (e) {
    css.styleSheet.cssText = code;
  }
  head.appendChild(css);
}

优缺点 & 适用场景

简单讲讲 BigRender 优化的优缺点,以及适用场景。

优点很明显,因为减少了首屏 DOM 的渲染,所以能加快首屏加载的速度,并且能分块加载 js/css,非常适用于一些模块区分度很高的网站(个人觉得大型网站的模块区分度普遍越来越高了)。

缺点是需要更改 DOM 结构(DOM 节点的替换和渲染),可能会引起一些重排和重绘。一些没有开启 js 功能的用户将看不到延迟加载的内容(可以用 noscript 标签给出一个善意提醒)。最大的缺点可能是不利于 SEO,一些依赖于 SEO 的网站可能需要在 SEO 上下点功夫了,比如美团。

关于 SEO,可以看下 http://www.seoqx.com/lynx 这个网站,能模拟搜索引擎蜘蛛对网站的爬取情况。美团对于 BigRender 以及 SEO 解决方案 [美团网案例]改善BigRender技术导致的SEO问题

bigrender 通过减少 DOM 节点,加快首屏的渲染,但是,它也是有额外的性能损耗的,渲染前textarea 里面的 html 代码,在服务端把 html 代码保存在隐藏的 textarea 里面,所以在服务端会把 html 代码转义:尖括号等都被转义了,这个会增加服务器的压力;而且,这个改造只是前端的渲染,服务器依旧是一次计算所有的数据,输出所有的数据,这一点没有得到提高。

一般来说,使用都是后端拼接成 html 字符串,然后塞入 textarea 标签中,吐给前端。

demo

如果要做一个完整的 BigRender demo,可能比较复杂,还要涉及到后端。

之前学习 lazyload 时做过一个图片的延迟加载 demo,see http://hanzichi.github.io/cnblogs/2016/Feb/picture-lazyload/。因为 BigRender 是 lazyload 的加强版,所以简单地做了个 BigRender 版本的图片延迟加载 http://hanzichi.github.io/cnblogs/2016/Mar/bigrender/,实现的具体代码可以 check bigrender.js

其他

除了首页部分用了 textarea 做 BigRender 优化外,美团还用到了 script 标签做优化。比如 这个商品详情页

给 script 标签设置个非 “text/JavaScript” 的 type,可以下载这段 js,但不执行,这种做法似曾相识,在 labjs 中看到过。

更多可以参考 前端优化三续:用script存放html代码来减少DOM节点数

Read More

[转载]使用nodejs爬取拉勾苏州和上海的.NET职位信息 - Agile.Zhou(kklldog) - 博客园

mikel阅读(752)

来源: [转载]使用nodejs爬取拉勾苏州和上海的.NET职位信息 – Agile.Zhou(kklldog) – 博客园

最近开始找工作,本人苏州,面了几家都没有结果很是伤心。在拉勾上按照城市苏州关键 字.NET来搜索一共才80来个职位,再用薪水一过滤,基本上没几个能投了。再加上最近苏州的房价蹭蹭的长,房贷压力也是非常大,所以有点想往上海去发 展。闲来无聊写了个小爬虫,爬了下苏州跟上海的.NET职位的信息,然后简单对比了一下。

是的小弟擅长.NET,为啥用nodejs?因为前几天有家公司给了个机会可以转nodejs,所以我是用来练手的,不过后来也泡汤了,但是还是花两晚写完了。刚学,代码丑轻喷哈!

一:如何爬取拉勾的数据

这个其实非常简单,本来还以为要用正则去分析html,其实拉勾分页提了ajax的接口,可以直接用http去访问。打开神器Chrome的F12一看便知。

这是用nodejs模拟分页请求的代码:

复制代码
var getData = function (kd,city,pn) {
    var mongo = require('./mongo');
    var http = require('http');
    var queryString = require('querystring');

    var postData=queryString.stringify({
        'pn':pn,
        'kd':kd,
        'first':false
    });

    var options = {
        hostname:'www.lagou.com',
        method:'POST',
        path:'/jobs/positionAjax.json?px=default&city='+city,
        headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': postData.length
        }
    };
    
    var postResult = '';
    
    var req = http.request(options,(res)=>{
        console.log(`STATUS:${res.statusCode}`);
        res.setEncoding('utf8');
        res.on('data',(chunk)=>{
            postResult+=chunk;
        }); 
        res.on('end',()=>{
            console.log(`RESULT:${postResult}`);
            var jsonObj =JSON.parse(postResult);
            //insert into db
            jsonObj.content.result.forEach((item)=>{
                var salary = item.salary;
                //拆分3k-6k,易于统计
                var arr = salary.split('-');
                var min = arr[0].substring(0,arr[0].indexOf('k'));
                var max = arr.length>1? arr[1].substring(0,arr[1].indexOf('k')):min;
                item.salaryMin = parseInt(min);
                item.salaryMax = parseInt(max);
                
                mongo.save(city,item);
            });
            if(jsonObj.content.hasNextPage&&jsonObj.content.totalPageCount>pn){
                getData(kd,city,pn+1);
            }
        });
        req.on('error',(e)=>{
            console.log(`problem with request:${e.message}`);
        }); 
    });

    req.write(postData);
    req.end();
    console.log(`start to get data. pn:${pn} city:${city} kd:${kd}`);
};

exports.run = getData;
复制代码

二:数据存储在哪里

拉勾的分页接口返回的是json对象,那么自然是存mongoDb最简单了。

下面是mongoDb的封装:

复制代码
var save=function (city,jsonObj) {
    var Db = require('mongodb').Db;
    var Server = require('mongodb').Server;

    var db = new Db('test',new Server('localhost',27017))

    db.open((err,db)=>{
        var coll = db.collection(city);
        coll.save(jsonObj,(err,r)=>{
            if(!err){
               console.log('save to '+city); 
            }
            
            db.close();
        });
        
    });
};

var removeAll = function (city,callback) {
    var Db = require('mongodb').Db;
    var Server = require('mongodb').Server;

    var db = new Db('test',new Server('localhost',27017))

    db.open((err,db)=>{
        var coll = db.collection(city);
        coll.remove((err,numOfRows)=>{
            if(!err){
                console.log(`${city} collection be removed. ${numOfRows}`);
            }
            db.close();
            callback(err);
        });
      
    });
};

var readAll=function (city,callback) {
    var Db = require('mongodb').Db;
    var Server = require('mongodb').Server;

    var db = new Db('test',new Server('localhost',27017))

    db.open((err,db)=>{
        var coll = db.collection(city);
        var cursor = coll.find();
        cursor.toArray((err,results)=>{
            if(!err){
                callback(results);
                //db.close();        
            }
            db.close();
        });
    });
}

exports.save = save;
exports.removeAll = removeAll;
exports.readAll = readAll;
复制代码

三:如何展示数据

使用nodejs自带的httpServer,接受到请求的时候直接读取一个html文件,然后把对比的信息填入html文本里,用一个h5的chart来展示

下面是服务器的代码:

复制代码
var http = require('http');
var fs = require('fs');
var stati = require('./statistics');
var szStati = {text:'SuZhou'};
var shStati = {text:'ShangHai'};

var server=new http.Server();  
server.on('request',function(req,res){  
    res.writeHead(200,{'Content-Type':'text/html'});  
    
    fs.readFile('./index.html','utf8',(err,data)=>{
        if (err) {
            throw err;
        }
        console.log(data);
        // res.write(data);
        // res.end();
        stati.statiSalary('苏州',(results)=>{
            szStati.values = results;
            stati.statiSalary('上海',(results)=>{
                shStati.values = results;
                var series =[szStati,shStati];
                var strSeries = JSON.stringify(series);
                console.log(strSeries);
                
                data = data.replace('@series',strSeries);
                console.log(data);
                
                res.write(data);
                res.end();
            });
        });
    });
});  
  
server.listen(3000);  
console.log('http server started...port:3000');
复制代码

四:统计结果

统计按照 0-5k,5-10k,10-15k,15-20k,20-25k,>25k这几个区间按照职位的数量进行统计。

0-5k:上海是苏州的4倍

5-10k:上海是苏州的4倍

10-15k:上海是苏州的9倍

15-20k:上海是苏州的12倍

20-25k:上海是苏州的17倍

>25k:上海是苏州的26倍

可以看到从10-15k开始的职位,上海的数量是苏州的10多倍,越是高薪的职位倍数越高。由此可以看出,苏州跟上海的差距还是非常大的。苏州政府 一直沾沾自喜,觉得自己在互联网圈子有多牛逼,搞了一堆孵化器,但其实拿的出手的公司有几家呢,一只手都数过来了,跟北上广深一线还是差的很远呢,还是要 努力啊。

恐怕我也要背井离乡去上海的寻找未来了。

还没学会用VS Code上传到github上,先直接上传代码吧:lagouSpider.zip

[转载]微信企业付款开发 C# - LLorJJ999 - 博客园

mikel阅读(1220)

来源: [转载]微信企业付款开发 C# – LLorJJ999 – 博客园

一、第一步:需要准备的东东

<add key=”sAppID” value=”wxf2303b260*******”/>                           // 开发者应用ID ,如图一

<add key=”sAppSecret” value=”5b83018b0b69c4231c14a2a25*******”/>    //开发者应用密钥,如图一

<add key=”sPartnerKey” value=”E07D38C4EC0C9B42BF808633*******”/>   //商户秘钥           如图二

<add key=”sPartner” value=”**********”/>                  // 商户号            申请微信支付通过后,收到的邮件里面有, 10位的商户号

 

    

    (图一),登录地址:https://mp.weixin.qq.com/

 

(图二,你自己设置的32位秘钥),登录地址:https://pay.weixin.qq.com/index.php/home/login?return_url=%2F

 

 

二、第二步:安装证书,windows下面选择.p12格式的证书;取证书时一定得用 绝对路径(如:D:\wwwroot\BusinessCard\weixin\businesscard\cert\apiclient_cert.p12)

      证书pkcs12格式 (apiclient_cert.p12)

 

三、第三步:帐户里面必须有钱,如下图

 

四、第四步:源码如下:

 

复制代码
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;

namespace BusinessCard.Web.Code
{
    public class Class1
    {
        /// <summary>
        /// 企业付款给个人,直接入帐到微信钱包中
        /// </summary>

        public static string TENPAY = "1";
        public static string APPID = Vincent._WebConfig.GetAppSettingsString("sAppID");              //开发者应用ID
        public static string PARTNER = Vincent._WebConfig.GetAppSettingsString("sPartner");          //商户号
        public static string APPSECRET = Vincent._WebConfig.GetAppSettingsString("sAppSecret");      //开发者应用密钥
        public static string PARTNER_KEY = Vincent._WebConfig.GetAppSettingsString("sPartnerKey");   //商户秘钥

        public const string URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";

        //服务器异步通知页面路径(流量卡)
        public static string WebUrl = Vincent._WebConfig.GetAppSettingsString("WebUrl");
        public static readonly string NOTIFY_URL_Card_Store = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx";// ConfigurationManager.AppSettings["WXPayNotify_URL_CardStore"].ToString();
        public static readonly string NOTIFY_URL_Card_User = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx"; //ConfigurationManager.AppSettings["WXPayNotify_URL_CardUser"].ToString();
        public static readonly string NOTIFY_URL_HB_Store = "http://" + WebUrl + "/weixinpay/WXPayNotify_URL.aspx";// ConfigurationManager.AppSettings["WXPayNotify_URL_CardStore"].ToString();

        //=======【代理服务器设置】===================================
        /* 默认IP和端口号分别为0.0.0.0和0,此时不开启代理(如有需要才设置)
        */
        public const string PROXY_URL = "http://10.152.18.220:8080";

        //=======【证书路径设置】===================================== 
        /* 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要)
        */
        public const string SSLCERT_PATH = "weixin\\businesscard\\cert\\apiclient_cert.p12";
        public static string SSLCERT_PASSWORD = PARTNER;


        /// <summary>
        /// 企业付款给个人
        /// </summary>       
        /// <returns></returns>
        public static string EnterprisePay(string Bill_No, string toOpenid, decimal Charge_Amt, string userName, string title)
        {

            //公众账号appid mch_appid 是 wx8888888888888888 String 微信分配的公众账号ID(企业号corpid即为此appId) 
            //商户号 mchid 是 1900000109 String(32) 微信支付分配的商户号 
            //设备号 device_info 否 013467007045764 String(32) 微信支付分配的终端设备号 
            //随机字符串 nonce_str 是 5K8264ILTKCH16CQ2502SI8ZNMTM67VS String(32) 随机字符串,不长于32位 
            //签名 sign 是 C380BEC2BFD727A4B6845133519F3AD6 String(32) 签名,详见签名算法 
            //商户订单号 partner_trade_no 是 10000098201411111234567890 String 商户订单号,需保持唯一性 
            //用户openid openid 是 oxTWIuGaIt6gTKsQRLau2M0yL16E String 商户appid下,某用户的openid 
            //校验用户姓名选项 check_name 是 OPTION_CHECK String NO_CHECK:不校验真实姓名 
            //FORCE_CHECK:强校验真实姓名(未实名认证的用户会校验失败,无法转账) 
            //OPTION_CHECK:针对已实名认证的用户才校验真实姓名(未实名认证用户不校验,可以转账成功) 
            //收款用户姓名 re_user_name 可选 马花花 String 收款用户真实姓名。 
            // 如果check_name设置为FORCE_CHECK或OPTION_CHECK,则必填用户真实姓名 
            //金额 amount 是 10099 int 企业付款金额,单位为分 
            //企业付款描述信息 desc 是 理赔 String 企业付款操作说明信息。必填。 
            //Ip地址 spbill_create_ip 是 192.168.0.1 String(32) 调用接口的机器Ip地址 

            Bill_No = PARTNER + getTimestamp() + Bill_No;  //订单号组成 商户号 + 随机时间串 + 记录ID

            //设置package订单参数
            SortedDictionary<string, string> dic = new SortedDictionary<string, string>();

            string total_fee = (Charge_Amt * 100).ToString("f0");
            string wx_nonceStr = Guid.NewGuid().ToString().Replace("-", "");    //Interface_WxPay.getNoncestr();

            dic.Add("mch_appid", APPID);
            dic.Add("mchid", PARTNER);//财付通帐号商家
            //dic.Add("device_info", "013467007045711");//可为空
            dic.Add("nonce_str", wx_nonceStr);
            dic.Add("partner_trade_no", Bill_No);
            dic.Add("openid", toOpenid);
            dic.Add("check_name", "NO_CHECK");
            dic.Add("amount", total_fee);
            dic.Add("desc", title);//商品描述
            dic.Add("spbill_create_ip", "211.149.234.224");   //用户的公网ip,不是商户服务器IP
            //生成签名

            string get_sign = BuildRequest(dic, PARTNER_KEY);


            Vincent._Log.SaveMessage("第一步 get_sign:" + get_sign);

            string _req_data = "<xml>";
            _req_data += "<mch_appid>" + APPID + "</mch_appid>";
            _req_data += "<mchid>" + PARTNER + "</mchid>";
            _req_data += "<nonce_str>" + wx_nonceStr + "</nonce_str>";
            _req_data += "<partner_trade_no>" + Bill_No + "</partner_trade_no>";
            _req_data += "<openid>" + toOpenid + "</openid>";
            _req_data += "<check_name>NO_CHECK</check_name>";
            _req_data += "<amount>" + total_fee + "</amount>";
            _req_data += "<desc>" + title + "</desc>";
            _req_data += "<spbill_create_ip>211.149.234.224</spbill_create_ip>";
            _req_data += "<sign>" + get_sign + "</sign>";
            _req_data += "</xml>";

            Vincent._Log.SaveMessage("企业付款生成的xml:" + _req_data.Trim());

            var result = HttpPost(URL, _req_data.Trim(), true, 300);
            //var result = HttpPost(URL, _req_data, Encoding.UTF8);
            Vincent._Log.SaveMessage("返回结果:" + result);

            return result;

            //ReturnValue retValue = StreamReaderUtils.StreamReader(URL, Encoding.UTF8.GetBytes(_req_data), System.Text.Encoding.UTF8, true);
            //Vincent._Log.SaveMessage("返回结果:" + retValue.ErrorCode);
            //return retValue.ErrorCode;            
        }

        public static string getTimestamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        public static string BuildRequest(SortedDictionary<string, string> sParaTemp, string key)
        {
            //获取过滤后的数组
            Dictionary<string, string> dicPara = new Dictionary<string, string>();
            dicPara = FilterPara(sParaTemp);

            //组合参数数组
            string prestr = CreateLinkString(dicPara);
            //拼接支付密钥
            string stringSignTemp = prestr + "&key=" + key;

            Vincent._Log.SaveMessage("生成签名的参数:" + stringSignTemp);

            //获得加密结果
            string myMd5Str = GetMD5(stringSignTemp.Trim());

            //返回转换为大写的加密串
            return myMd5Str.ToUpper();
        }

        /// <summary>
        /// 除去数组中的空值和签名参数并以字母a到z的顺序排序
        /// </summary>
        /// <param name="dicArrayPre">过滤前的参数组</param>
        /// <returns>过滤后的参数组</returns>
        public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
        {
            Dictionary<string, string> dicArray = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> temp in dicArrayPre)
            {
                if (temp.Key != "sign" && !string.IsNullOrEmpty(temp.Value))
                {
                    dicArray.Add(temp.Key, temp.Value);
                }
            }

            return dicArray;
        }

        //组合参数数组
        public static string CreateLinkString(Dictionary<string, string> dicArray)
        {
            StringBuilder prestr = new StringBuilder();
            foreach (KeyValuePair<string, string> temp in dicArray)
            {
                prestr.Append(temp.Key + "=" + temp.Value + "&");
            }

            int nLen = prestr.Length;
            prestr.Remove(nLen - 1, 1);

            return prestr.ToString();
        }

        //加密
        public static string GetMD5(string pwd)
        {
            MD5 md5Hasher = MD5.Create();

            byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(pwd));

            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            return sBuilder.ToString();
        }


        public static string HttpPost(string postUrl, string paramData, Encoding dataEncode)
        {
            string ret = string.Empty;
            try
            {
                byte[] byteArray = dataEncode.GetBytes(paramData); //转化
                HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl));
                webReq.Method = "POST";
                webReq.ContentType = "application/x-www-form-urlencoded";

                webReq.ContentLength = byteArray.Length;
                Stream newStream = webReq.GetRequestStream();
                newStream.Write(byteArray, 0, byteArray.Length);//写入参数
                newStream.Close();
                HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default);
                ret = sr.ReadToEnd();
                sr.Close();
                response.Close();
                newStream.Close();
            }
            catch (Exception ex)
            {
                Vincent._Log.SaveMessage("Post提交异常:" + ex.Message);
            }
            return ret;
        }

        public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            //直接确认,否则打不开    
            return true;
        }

        /// <summary>
        /// post提交支付
        /// </summary>
        /// <param name="xml"></param>
        /// <param name="url"></param>
        /// <param name="isUseCert">是否使用证书</param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static string HttpPost(string url, string xml, bool isUseCert, int timeout)
        {
            System.GC.Collect();//垃圾回收,回收没有正常关闭的http连接

            string result = "";//返回结果

            HttpWebRequest request = null;
            HttpWebResponse response = null;
            Stream reqStream = null;

            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "POST";
                request.Timeout = timeout * 1000;

                //设置代理服务器
                //WebProxy proxy = new WebProxy();                          //定义一个网关对象
                //proxy.Address = new Uri(PROXY_URL);              //网关服务器端口:端口
                //request.Proxy = proxy;

                //设置POST的数据类型和长度
                request.ContentType = "text/xml";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
                request.ContentLength = data.Length;

                //是否使用证书
                if (isUseCert)
                {
                    string path = HttpContext.Current.Request.PhysicalApplicationPath;
                    //X509Certificate2 cert = new X509Certificate2(path + SSLCERT_PATH, SSLCERT_PASSWORD);

                    //将上面的改成
                    X509Certificate2 cert = new X509Certificate2(path + SSLCERT_PATH, SSLCERT_PASSWORD, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);//线上发布需要添加

                    request.ClientCertificates.Add(cert);

                    Vincent._Log.SaveMessage("证书路径:" + (path + SSLCERT_PATH));

                    //Vincent._Log.SaveMessage("WxPayApi:PostXml used cert");
                }

                //往服务器写入数据
                reqStream = request.GetRequestStream();
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();

                //获取服务端返回
                response = (HttpWebResponse)request.GetResponse();

                //获取服务端返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (System.Threading.ThreadAbortException e)
            {
                Vincent._Log.SaveMessage("HttpService:Thread - caught ThreadAbortException - resetting.");
                Vincent._Log.SaveMessage("Exception message:" + e.Message);
                System.Threading.Thread.ResetAbort();
            }
            catch (WebException e)
            {
                Vincent._Log.SaveMessage("HttpService" + e.ToString());
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    Vincent._Log.SaveMessage("HttpService:StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
                    Vincent._Log.SaveMessage("HttpService:StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
                }
                throw new Exception(e.ToString());
            }
            catch (Exception e)
            {
                Vincent._Log.SaveMessage("HttpService" + e.ToString());
                throw new Exception(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }

        /// <summary>
        /// 处理http GET请求,返回数据
        /// </summary>
        /// <param name="url">请求的url地址</param>
        /// <returns>http GET成功后返回的数据,失败抛WebException异常</returns>
        public static string Get(string url)
        {
            System.GC.Collect();
            string result = "";

            HttpWebRequest request = null;
            HttpWebResponse response = null;

            //请求url以获取数据
            try
            {
                //设置最大连接数
                ServicePointManager.DefaultConnectionLimit = 200;
                //设置https验证方式
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    ServicePointManager.ServerCertificateValidationCallback =
                            new RemoteCertificateValidationCallback(CheckValidationResult);
                }

                /***************************************************************
                * 下面设置HttpWebRequest的相关属性
                * ************************************************************/
                request = (HttpWebRequest)WebRequest.Create(url);

                request.Method = "GET";

                //设置代理
                WebProxy proxy = new WebProxy();
                proxy.Address = new Uri(PROXY_URL);
                request.Proxy = proxy;

                //获取服务器返回
                response = (HttpWebResponse)request.GetResponse();

                //获取HTTP返回数据
                StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                result = sr.ReadToEnd().Trim();
                sr.Close();
            }
            catch (System.Threading.ThreadAbortException e)
            {
                Vincent._Log.SaveMessage("HttpService:Thread - caught ThreadAbortException - resetting.");
                Vincent._Log.SaveMessage("Exception message: " + e.Message);
                System.Threading.Thread.ResetAbort();
            }
            catch (WebException e)
            {
                Vincent._Log.SaveMessage("HttpService" + e.ToString());
                if (e.Status == WebExceptionStatus.ProtocolError)
                {
                    Vincent._Log.SaveMessage("HttpService:StatusCode : " + ((HttpWebResponse)e.Response).StatusCode);
                    Vincent._Log.SaveMessage("HttpService:StatusDescription : " + ((HttpWebResponse)e.Response).StatusDescription);
                }
                throw new Exception(e.ToString());
            }
            catch (Exception e)
            {
                Vincent._Log.SaveMessage("HttpService" + e.ToString());
                throw new Exception(e.ToString());
            }
            finally
            {
                //关闭连接和流
                if (response != null)
                {
                    response.Close();
                }
                if (request != null)
                {
                    request.Abort();
                }
            }
            return result;
        }


    }
}
复制代码

[转载]零OCR基础6行代码实现C#验证码识别 - Я!ńɡ - 博客园

mikel阅读(1058)

来源: [转载]零OCR基础6行代码实现C#验证码识别 – Я!ńɡ – 博客园

这两天因为工作需要,要到某个网站采集信息,一是要模拟登陆,二是要破解验证码,本想用 第三方付费打码,但是想想网上免费的代码也挺多的,于是乎准备从网上撸点代码下来,谁知道,撸了好多个都不行,本人以前也没接触过这方面的,代码无从下 手,最后不知道在哪个兄台博客找到一个国外的第三方开源OCR,说是强大的谷歌公司做维护,C++开发的,有.NET封装的链接库,甚好!
项目地址:https://github.com/tesseract-ocr/tesseract
语言库:https://github.com/tesseract-ocr/langdata
OCR语言训练:https://github.com/tesseract-ocr/tessdata

下面开始撸示例:

新建C#控制台,版本选择.NET 4.5

Tesseract ocr = new Tesseract();
ocr.SetVariable("tessedit_char_whitelist", "0123456789");
ocr.Init(@"D:\测试\Ocr\tessdata", "eng", true);

第一句就不用说了,第二句是设置识别的字符,例如,如果你要识别的验证码是A-Z0-9你就都写进来就OK了
第三句就是初始化OCR的语言训练配置,里面很多文件,只要写文件名小数点前面的就OK了

List<Word> result = ocr.DoOCR(bmp, Rectangle.Empty);
if(result.Count<=0)return;
string code = result[0].Text;

最后的Code就是识别出来的验证码了,这里验证码图片一定要转换为Bitmap对象才行,记得用完了释放Bitmap对象!

下面是我测试截图:

上面是验证码,下面文件名是识别出来的结果命名保存的文件!当然验证码是经过处理的,原始的验证码图片是酱紫的:

验证码图片太小,OCR识别不了,而且默认情况下,要是白底,黑子才能识别,所以网上的验证码一定要先自己二值化处理并且清除掉背景色,再进行识别!
我这里的处理方式是二值化之后,把图片放大三倍,不要担心看着有锯齿,OCR可以识别的
当初我把图片放大两倍,发现有的时候8会被识别成3,所以我干脆又放大了一倍,发现不存在这个问题了,虽然看起来锯齿感很明显,但是OCR不管美丑

 

你是不是参照案例撸码了,运行了?然后你发现程序运行报错了?

这里要在程序的app.config的startup节点加上 useLegacyV2RuntimeActivationPolicy=”true”节点,详细如下:

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
</configuration>
复制代码

然后再运行,是不是可以识别出来了,就是这么简单!

[转载][PHP]利用XAMPP搭建本地服务器, 然后利用iOS客户端上传数据到本地服务器中(三. PHP端代码实现) - M_Lee - 博客园

mikel阅读(972)

来源: [转载][PHP]利用XAMPP搭建本地服务器, 然后利用iOS客户端上传数据到本地服务器中(三. PHP端代码实现) – M_Lee – 博客园

一.安装XAMPP   http://www.cnblogs.com/lidongxu/p/5256330.html

二. 配置MySQL http://www.cnblogs.com/lidongxu/p/5256515.html

然后呢, 今天我们就来接触下PHP开发语言

1. 首先呢, 需要在我们本机服务器文件夹资源下新建个.php文件,   废话嘛(你要写php啦!)

2. 在register.php 输入以下代码

复制代码
<?php 

// 1. 获取客户端利用post方式网络请求的body里的字段对应的value (这个字段
// 是这里规定的, 前端必须遵守这个name2, pass2等key值)
$nameP = $_POST['name2'];
$passP = $_POST['pass2'];
$ageP = $_POST['age2'];
$telephoneP = $_POST['telephone2'];

// 2. 建立数据库连接 (127.0.0.1 数据库所在的ip地址)
// root 是数据库用户名(默认的)
// "" 密码(默认是空)
$con = mysql_connect("127.0.0.1", "root", "");
$myCon = mysql_select_db("lidongxu", $con);

// 3. 先查询, 如果存在就不要在插入了
$select = "select userName from User where userName = '$nameP'";
$seleResult = mysql_query($select);

// 4. 如果查到了, 说明已经存在这个用户了, 则返回-1给客户端代表已经注册过了
if (mysql_num_rows($seleResult)) {

// success 就是key值 对应的value 就是后面的字符串
    $a = array();
    $a['success'] = "-1";
    $a['status'] = "have";
    $arr = json_encode($a);
    echo $arr;
}
// 5. 如果没注册过, 那么
else {

// 6. 把数据都插入到mysql数据库中
    $sql = "insert into User values('$nameP', '$passP', '$ageP', '$telephoneP')";

    $result = mysql_query($sql);

    if ($result == 1) { // 7. 代表执行成功
        $a = array();
        $a['success'] = "1";
        $a['status'] = "ok";
        $arr = json_encode($a);
        echo $arr;

    }
    else { // 8. 代表插入失败
        $a = array();
        $a['success'] = "0";
        $a['status'] = "no";
        $arr = json_encode($a);
        echo $arr;
    }

}

// 9. 接收用户头像图片
// 9.1. 接收图片传到服务器上默认的临时文件路径以及名字 (uploadfile 给前台使用的
// 字段)
$url = $_FILES["uploadimageFile"]["tmp_name"];

// 9.2 获取根路径下的downloads文件夹下的路径(download2 需要手动
// 去本地创建)
$destination_folder = $_SERVER['DOCUMENT_ROOT'].'/download2/';


    // 9.3拼接要作为服务器上保存的文件名字
    $newfname = $destination_folder .(string)$nameP.'.jpg'; //set your file ext


// 打开连接  rb+ 读写打开一个二进制文件,允许读写数据,文件必须存在。
// 获取客户端上传到缓存文件夹下的文件
    $file = fopen ($url, "rb");

    if ($file) {
        // a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
      // 获取要把客户端传递过来的文件复制到新的文件夹下的名字
      $newf = fopen ($newfname, "a"); 

      if ($newf)
          // 检查文件是否结束,如结束,则返回非零值
      while(!feof($file)) {
          // 开始从某个文件读取1MB 然后写入到新的路径1MB
        fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );

      }
    }

    if ($file) {
        // 关闭文件链接
      fclose($file);
    }

    if ($newf) {
      fclose($newf);
    }



 ?>
复制代码

3. 然后在本地服务器文件夹下新建download2文件夹

4. 然后再把登录的php代码也写了吧!在htdocs文件夹下, 新建loginGet.php文件 然后插入代码

复制代码
<?php 

// 1. 获取GET网络请求网址里的key值对应的value
// 声明变量name1 和pass1 接收
$name1 = $_GET['name'];
$pass1 = $_GET['pass'];

// 2. 建立数据库连接
// 参数1: 数据库所在的服务器的地址(本机127.0.0.1或者localhost)
// 参数2: MySql数据库的账户(默认root)
// 参数3: MySql数据库的密码(默认无)
$con = mysql_connect("127.0.0.1", "root", "");

// 参数1: 自己建立的数据库的名字
$myCon = mysql_select_db("lidongxu", $con);

// 3. 执行查询 (利用用户名和密码进行匹配查找, 如果找到了随意返回userName(用户名))
$sql = "select * from User where userName = '$name1' And password = '$pass1'";

// 4. 接收结果
$result = mysql_query($sql);

// 4.2 如果查询结果为空的话
if(mysql_num_rows($result) == 0) {
        $a = array();
        $a['success'] = "0";
        $a['name'] = "null";
        $a['status'] = "no";
        $arr = json_encode($a);
        echo $arr;

        
}
else {
// 5. 取出本条记录
$row = mysql_fetch_row($result);
    
    
        $a = array();
        $a['success'] = "1";
        $a['name'] = $row[0];
        $a['age'] = $row[2];
        $a['telephone'] = $row[3];
        $a['status'] = "ok";
        $arr = json_encode($a);
        echo $arr;
    
}


 ?>
复制代码

到此, php暂时告一段路, 然后进行iOS段代码开发(开心不???)

 

来写iOS 代码吧………..      http://www.cnblogs.com/lidongxu/p/5267753.html

 

努力做一名,让再菜的菜鸟都能看明白,学明白的博客的制造者

[转载]Linux下安装SVN服务端小白教程 - 六仙庵 - 博客园

mikel阅读(805)

来源: [转载]Linux下安装SVN服务端小白教程 – 六仙庵 – 博客园

安装

使用yum安装非常简单:

yum install subversion

配置

创建仓库

我们这里在/home下建立一个名为svn的仓库(repository),以后所有代码都放在这个下面,创建成功后在svn下面多了几个文件夹。

[root@localhost /]# cd /home
[root@localhost home]# mkdir svn
[root@localhost home]# svnadmin create /home/svn
[root@localhost home]# ls svn
conf  db  format  hooks  locks  README.txt

我们这里特别关注一下conf文件夹,这个是存放配置文件的

[root@localhost home]# cd svn/conf
[root@localhost conf]# ls
authz  passwd  svnserve.conf

其中:

  • authz 是权限控制文件
  • passwd 是帐号密码文件
  • svnserve.conf 是SVN服务配置文件

接下来我们依次修改这3个文件。

配置passwd

[root@localhost conf]# vi passwd 
[users]
test1=123456
test2=123456

上面的例子中我们创建了2个用户,一个test1,一个test2

配置authz

[root@localhost conf]# vi authz 
[/]
liuxianan=rw
test1=r
test2=r
*=

上面配置的含义是,liuxianan/home/svn/下所有文件具有可读可写权限,test只有只读权限,除此之外,其它用户均无任何权限,最后一行*=很重要不能少。

拓展:使用用户分组

这个我一般不用,但是记录下来。

还是这个文件:

[root@localhost conf]# vi authz
[groups]
group1 = liuxianan
group2 = test1,test2
[/]
@group1 = rw
@group2 = r
* =

上面配置中创建了2个分组,分组1的用户可读可写,分组2的用户只读。

格式说明:

版本库目录格式:
[<版本库>:/项目/目录]
@<用户组名> = <权限>
<用户名> = <权限>

配置svnserve.conf

[root@localhost conf]# vi svnserve.conf 
打开下面的5个注释
anon-access = read #匿名用户可读
auth-access = write #授权用户可写
password-db = passwd #使用哪个文件作为账号文件
authz-db = authz #使用哪个文件作为权限文件
realm = /home/svn # 认证空间名,版本库所在目录

2点注意:

  • 最后一行的realm记得改成你的svn目录
  • 打开注释时切记前面不要留有空格,否则可能有问题(网上说的,我没有亲测)

启动与停止

[root@localhost conf]# svnserve -d -r /home/svn(启动)
[root@localhost conf]#killall svnserve(停止)

上述启动命令中,-d表示守护进程, -r 表示在后台执行。停止还可以采用杀死进程的方式:

[root@localhost conf]# ps -ef|grep svnserve
root      4908     1  0 21:32 ?        00:00:00 svnserve -d -r /home/svn
root      4949  4822  0 22:05 pts/0    00:00:00 grep svnserve
[root@localhost conf]# kill -9 4908

最后来个总的截图:

客户端连接

这里使用TortoiseSVN,输入地址svn://你的IP 即可,不出意外输入用户名和密码就能连接成功了。

默认端口3690,如果你修改了端口,那么要记得加上端口号。

总结

总的来说,如果你不需要杂七杂八的权限配置只是自己一个人用的话,安装配置还是比较简单的,并不像网上说的那么麻烦,我按照网上的方法一次性成功了。

扩展:yum安装路径

以svn为例:

# rpm -qa | grep subversion
subversion-1.6.11-15.el6_7.x86_64
# rpm -ql subversion-1.6.11-15.el6_7.x86_64
...
/usr/share/doc/subversion-1.6.11
/usr/share/doc/subversion-1.6.11/BUGS
/usr/share/doc/subversion-1.6.11/CHANGES
...

说明:

  • rpm -qa 查询所有安装的rpm包,可以配合grep命令。
  • rpm -qi 查询某个具体包的介绍。
  • rpm -ql 列出某个具体包的所有文件

rpm几个默认安装路径:

/etc    一些设置文件放置的目录
/usr/bin    一些可执行文件
/usr/lib64  一些程序使用的动态函数库
/usr/share/doc  一些基本的软件使用手册与帮助文档
/usr/share/man  一些man page文件

[转载]ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo - Dr_Hao - 博客园

mikel阅读(932)

来源: [转载]ASP.NET MVC+JQueryEasyUI1.4+ADO.NET Demo – Dr_Hao – 博客园

DrHao.CMS整体参考源代码:链接:http://pan.baidu.com/s/1jHfpkmM%20 密码:f2t8

MVCBlog(ASP.NET MVC 4.0+EF 简单Demo) 链接:http://pan.baidu.com/s/1bkVvcU  密码:1c2f

Q:我在DrHao.CMS中定义一个BaseController控制器,代码如下:

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Mvc;
 6 using System.Web.Providers.Entities;
 7 
 8 namespace DrHao.CMS.WebApp.Controllers
 9 {
10     public class BaseController : Controller
11     {
12         //
13         // GET: /Base/
14         protected override void OnActionExecuting(ActionExecutingContext filterContext)
15         {
16             if (Session["UserInfo"]==null)
17             {
18                 //没效果,还是会执行Action的方法
19                 filterContext.HttpContext.Response.Redirect("/Login/Index");
20             }
21             base.OnActionExecuting(filterContext);
22         }
23 
24     }
25 }
复制代码

运行DrHao.CMS 直接访问 /Home/Index ,HomeController继承BaseController 代码如下:

复制代码
 1 using DrHao.CMS.Model;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 
 8 namespace DrHao.CMS.WebApp.Controllers
 9 {
10     public class HomeController : BaseController
11     {
12         //
13         // GET: /Home/
14 
15         public ActionResult Index()
16         {
17             UserInfo user = Session["UserInfo"] as UserInfo;
18             //user判断 正常情况下不需要写
19             if (user == null)
20             {
21                 return Redirect("/Login/Index");
22             }
23             else
24             {
25                 ViewBag.userLogin = user.UUserName;
26                 return View();
27             }
28 
29         }
30 
31     }
32 }
复制代码

正常情况下,在没有登陆当前用户的时候,直接访问/Home/Index,会执行BaseController中的 protected override void OnActionExecuting(ActionExecutingContext filterContext)方法,判断当前用户没有登陆,则直接跳转,不会执行/Home/Index Action中的方法,但实际运行效果,会继续执行/Home/Index中的方法(若在/Home/Index中不加入判断,则直接抛出异常信息,user不能为null)

1:直接访问/Home/Index View,执行代码如下:

2:判断当前Session[“UserInfo”]==null,执行跳转代码,但是还会继续执行base.OnActionExecuting(filterContext);方法

3:执行完BaseController中OnActionExecuting方法,则会继续执行HomeController控制器下的Index Action(按照我的理解不应该继续执行)

关于这点疑问,各位博友,有什么好的办法或者见解,帮我解惑一下,谢谢!

code write the life, programe change the world

dede织梦data目录正确迁移及引起的问题解决方法

mikel阅读(914)

  关于将dede织梦data目录迁移出web目录织梦官方提供了一个教程,但是如果 你是按照他们提供的教程做的话会出现很多问题。比如验证码问题,图片显示问题等等一大堆。织梦官方这种是很不负责任的,因为那个教程有很大缺陷。这里跟大 家提供一个完整版本的如何将dede织梦data目录正确迁移,以及按照官方版本教程迁移出现问题的解决办法。这里先看看官方的吧,然后我再补充。

1、将data目录转移到非Web目录

我们这里举例“D:\dedecms\v57”为我们系统的根目录,我们需要将目录下的data文件夹(如图1)迁移要上一级目录(非Web目录),简单的办法直接剪切或者拷贝即可。

  我们移动上一级目录中,注意观察文件路径。

  2.修改DEDEDATA目录的配置常量

找到系统目录下/include/common.inc.php文件,修改DEDEDATA常量为你的系统目录。

  3.配置tplcache缓存文件目录

进入系统后台,在配置中修改tplcache目录为你想对目录。

   到了这里官方说教程已经完成,可是如果你信了那就麻烦了。你会碰到很多问题。这么草率的搬离问题很多的比如,我们常见的网站地图和生成的JS 文件,全部会导致路径不正确。例如发现移动后有两点问题,第一、后台登陆不显示验证码了,第二、联动类别后台发布的时候不显示.移动后发布文章时候联动类 别不显示和后台登陆不显示验证码。等等,即使你想要转移回去发现问题依然存在。其实真正正确的转移方法是:你需要把整个程序里所有关于调用到’/.. /data’ 的部分全部换掉。而不仅仅是上面官方说的那几个。下面就挨个说下经常碰到的问题解决方法。

转移data目录后验证码不显示或者输入验证码一直提示错误

不显示验证码的同学请改一下/include/vdimgck.php这个文件 这个文件里也调用了DATA里的文件也可以改路径,把带有这个 /../data 改成你现在的路径。

$im = @imagecreatefromjpeg(dirname(__FILE__).'/data/vdcode.jpg');

首页index.php文件也需要修改

还需要把首页中index.php中的/data/改为/../data。也就是下面这句。

  if(!file_exists(dirname(__FILE__).'/data/common.inc.php'))
  {
  header('Location:install/index.php');
  exit();
  }

DEDECMS默认生成的rss地图以及网站地图等都是生成在DATA的文件夹中,但是这个是一个非常重要的文件夹,一般我们在 Robots.txt 是禁止搜索引擎爬行这文件夹的,这就造成了,我们生成了地图,但是搜索根本就找不到的尴尬,下面就教大家如何更改自动生成的目录

下面是详细的步骤:

1,首先登录ftp,在根目录下建立rss文件夹

2,修改根目录下你的管理员文件夹(默认是dede)下的makehtml_map.php文件

复制代码
  将17行的$cfg_cmspath."/data/sitemap.html";改为

  $cfg_cmspath."/sitemap.html";

  将22行的$cfg_cmspath."/data/rssmap.html";改为

  $cfg_cmspath."/rssmap.html";
复制代码

17行是普通网站地图,22行是RSS的网站地图

3,修改根目录下include下面的arc.rssview.class.php

  将71行的$murl = $GLOBALS['cfg_cmspath']."/data/rss/".$this->TypeID.".xml";改为

  $murl = $GLOBALS['cfg_cmspath']."/rss/".$this->TypeID.".xml";

4,修改根目录下include下的sitemap.class.php

复制代码
  将57行的$typelink = $GLOBALS['cfg_cmsurl']."/data/rss/".$row->id.".xml";

  $typelink = $GLOBALS['cfg_cmsurl']."/rss/".$row->id.".xml";

  将94行的$typelink = $GLOBALS['cfg_cmsurl']."/data/rss/".$row->id.".xml";

  $typelink = $GLOBALS['cfg_cmsurl']."/rss/".$row->id.".xml";
复制代码

5,修改/templets/default模板文件head.htm

在11行左右找到

<li class="r3"><a href="{dede:global.cfg_dataurl/}/sitemap.html">网站地图</a></li>
<li class="r4"><a href="{dede:global.cfg_dataurl/}/rssmap.html">RSS订阅</a></li>

改为

<li class="r3"><a href="{dede:global.cfg_cmsurl/}/sitemap.html">网站地图</a></li>
<li class="r4"><a href="{dede:global.cfg_cmsurl/}/rssmap.html">RSS订阅</a></li>

6,进入后台,更新网站地图,更新RSS文件,更新主页。

[转载]2014年国人开发的最热门的.NET开源项目 TOP 25 - dapeng888 - 博客园

mikel阅读(839)

来源: [转载]2014年国人开发的最热门的.NET开源项目 TOP 25 – dapeng888 – 博客园

原文地址:http://www.cnphp6.com/archives/72213

奎宇工作室 / DotNetCodes C#

一些常用的功能性代码,可以减少许多开发时间,而且类与类之间没有什么依赖,每个类都可以单独拿出来使用

beyonehu / manual_dota C#

《刀塔传奇》开源项目,服务器+客户端,蛮牛主办深圳玩贝科技组织http://www.unitymanual.com/forum-p

oschina / wp7-app C#

OSCHINA 的 Windows Phone 7 客户端源码,可直接在 Marketplace 上搜索“开源中国”来安装此app

anycmd / anycmd C#

一个.net平台的完全开源的,完整支持rbac的,将会支持xacml、JavaScript的通用的权限框架、引擎、中间件、解决方案。

kerryjiang / SuperSocket C#

SuperSocket 是一个轻量级的可扩展的 Socket 开发框架,可用来构建一个服务器端 Socket 程序,而无需了解如何使用…

Scut / Scut C#

Scut游戏服务器引擎是使用C#语言开发,特别适用于手机网络游戏,支持使用Python脚本进行游戏开发;可以支持多种数据库:支持HTT…

nbboy / CommOAuth2 C#

支持国内淘宝,支付宝,新浪,微信,腾讯微博快捷登录

wojilu / wojilu C#

(1)一个 .net 平台下的全栈式、轻量级开发框架,包括 ORM、MVC、IOC、AOP、JSON、LOG 等,同时包括全套图文教程…

海洋饼干 / AForge.NET C#

AForge.NET 是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习…

10 奎宇工作室 / Asp.Net Mvc WebManger C#

基于asp.net mvc的开源网站管理系统

11 bobo2cj / iamge2text C#

识别出图片里的数字和字母

12 gsbhzh / GG C#

可在广域网部署运行的QQ高仿版 — GG叽叽。 项目地址:http://www.cnblogs.com/justnow/

13 cheng5x / Yc.QrCode C#

码晒客/疯狂创意二维码,底层 ,模版制作开源

14 longshine / Mina.NET C#

Mina.NET是.NET上的轻量级高性能网络程序框架,支持TCP、UDP和串口等多种传输通道,能够帮助开发者快速地开发高伸缩性的应用程序。

15 葡萄城控件 / ActiveReports C#

ActiveReports是一款在全球范围内应用非常广泛的报表控件,以提供.NET报表所需的全部报表设计功能领先于同类报表控件,包括对…

16 wangwei123 / easy4net C#

easy4net是一个轻量级orm框架,灵活在于可以自己编写复杂的SQL语句查询,简单在于几分钟内便能上手使用,并支持mySQL, m…

17 wobumang / wbm.weixinmpsdk C#

微信公众平台SDK。一个更方便,更快速的C#SDK,希望能帮助更多的朋友学习和使用

18 rainy_blue_sky / SmartHomeChat C#

用于局域网的聊天软件, 从其他开源平台上移植过来的, 感觉不错! 开发平台: VS2012 开发语言: …

19 bobo2cj / SimpleWinformFrame C#

简单的winform开发架子,客户端主程序(tabControl),客户端自动更新程序(WebClient),服务端更新列表生成器(XML)

20 _Jerry / JLib C#

C#类库

21 kerryjiang / SuperWebSocket C#

SuperWebSocket是WebSocket协议服务器端的.NET实现. 作为HTML5的一个重要新特性,WebSocket 规…

22 yqblog / yqblog C#

yqblog-基于MVC,Bootstrap的个人博客系统

23 Aimeast / GitCandy C#

GitCandy是一个开源的基于ASP.NET Mvc的轻量级Git服务端。 QQ交流群:200319579

24 xiaocong_soft / CheckUpdate.Net C#

Winform开发的检查更新程序。可用于Winform/WPF,主要功能包括更新文件、更新程序自身、下载安装包等。

25 奎宇工作室 / NoIIS C#

基于.net4.0的免装IIS运行程序的工具,只要安装.net4.0,就可以快速启动网站程序,为客户演示提供方便