兼容建议:(2017年初)
连淘宝都放弃 IE6 了,就不需要再坚持了;
IE7 跟错了老大(Vista),已经没有市场了;
当前市场份额最大的操作系统还是 Win7,所以 IE8 是必须要兼容的,就算国人都安装了国产浏览器,内核也未必会升到 IE9-11。
当然每个站的访客群体不同,具体还得参考网站统计数据来确定兼容级别。
为了友好,建议你在不打算兼容的浏览器上提供升级提示和新版下载链接。
如果是纯移动端,那么大胆地用 HTML5 就行了。
以下例举我遇到过的兼容问题:
浏览器版本 | 注意事项 |
IE6-7 | <input type="radio" /> 必须设置 name 才能被选中 |
IE6-7 | 不支持 console.log |
IE6-7 | 不支持 JSON.stringify |
所有 IE | 不支持 <input /> 新的 type 类型,查看详情 |

程序设计规范:
【推荐】上传的文件直接保存到文件存储服务(如阿里云 OSS),这样即使被上传了后门 shell,对网站服务器也不会有影响。
否则必须通过文件头来确定文件类型,检查文件十六进制的文件头和文件尾是否合法,并检查文件流中是否包含 php、evel 等字符。
不可直接使用客户端文件名来保存文件,特别是后缀名/扩展名。应生成随机文件名,并通过检验文件头来确定文件类型。必须由程序指定保存目录。
使用 OSS 的应直接上传,不要在 ECS 上临时存放或备份。如必须存放的,应按上述规范操作。
服务器安全设置
CentOS + nginx + PHP:
全站文件取消属性中的“执行”权限(chmod),因为这个“执行”与运行 PHP 无关。而需要上传文件的“目录”需要“执行”权限,原因是需要往该目录创建文件。
仅需要写入的目录或文件设置“写入”权限。如上传图片目录、ThinkPHP 的 Runtime 目录。
凡可写目录或文件均不允许运行 PHP / PY 等 除需要被直接访问的 PHP / PY 文件,其它动态文件均不允许被访问到,在 nginx 的配置文件中添加项,参:https://xoyozo.net/Blog/Details/nginx-location-if,若全站使用统一的入口文件访问,那么设置仅该文件允许运行 PHP 即可。通过 IO 方式被其它文件包含的文件,无需运行 PHP 权限。(“deny all”对 include 起作用,但对 IO 不起作用,因此 Runtime 目录可以继续为 ThinkPHP 提供缓存服务。)这一步非常有用。
使用与 nginx 网站用户不同的用户来部署网站文件,如宝塔面板 PHP 使用 www 用户,那么就使用 root 或其它新用户来上传文件,否则将导致全站目录和文件可写。有条件的建议不同网站使用不同的用户,可防止一个网站被入侵后导致其它网站文件或磁盘上的其它文件被泄露的风险(2022年10月2日从宝塔官方社区获悉,宝塔面板暂不支持使用非 www 用户创建并运行网站)。
Windows Server + IIS + ASP.NET:
配置每个磁盘的安全属性,拒绝“IIS_IUSRS”这个用户组的所有权限。只要设置驱动器即可,子文件夹和文件会自动继承。若运行 .NET Framework 项目,需要设置 C:\Windows\Microsoft.NET\Framework\v*.*.*****\Temporary ASP.NET Files\ 目录可修改写入权限,.NET Core 项目不需要此设置。
为每个网站创建一个新用户,仅隶属于“IIS_IUSRS”。网站根目录安全属性添加该用户,权限选择“读取”。(已测取消“读取与执行”不影响 PHP,“列出文件夹内容”视业务需求开启,建议关闭)。仅需要上传文件的目录或文件设置“修改”、“写入”权限。(修改对应修改文件,写入对应上传文件)
IIS 网站中设置“物理路径凭据”以及应用程序池的“标识”。
IIS 中设置写入目录的“处理程序映射”无脚本。

设规则:
属性-文件传输规则-全局
如果 时间 为 较旧 并且 传输 为 下载 那么 覆盖
如果 大小 为 不同 并且 传输 为 下载 那么 覆盖
如果没有匹配的规则,那么:跳过
建站点:
站点-站点管理器-新建站点
设好本地路径,传输 自定义规则 使用全局设置
队列:
连接站点,在需要备份的目录上右键,队列
在队列上右键,另存为
计划:
工具-计划-新建任务
选择队列文件,使用自定义规则
设置执行时间,Windows 密码
设置完成!

前言
最近在学习Web Api框架的时候接触到了async/await,这个特性是.NET 4.5引入的,由于之前对于异步编程不是很了解,所以花费了一些时间学习一下相关的知识,并整理成这篇博客,如果在阅读的过程中发现不对的地方,欢迎大家指正。
同步编程与异步编程
通常情况下,我们写的C#代码就是同步的,运行在同一个线程中,从程序的第一行代码到最后一句代码顺序执行。而异步编程的核心是使用多线程,通过让不同的线程执行不同的任务,实现不同代码的并行运行。
前台线程与后台线程
关于多线程,早在.NET2.0时代,基础类库中就提供了Thread实现。默认情况下,实例化一个Thread创建的是前台线程,只要有前台线程在运行,应用程序的进程就一直处于运行状态,以控制台应用程序为例,在Main方法中实例化一个Thread,这个Main方法就会等待Thread线程执行完毕才退出。而对于后台线程,应用程序将不考虑其是否执行完毕,只要应用程序的主线程和前台线程执行完毕就可以退出,退出后所有的后台线程将被自动终止。来看代码应该更清楚一些:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp { class Program { static void Main(string[] args) { Console.WriteLine("主线程开始"); //实例化Thread,默认创建前台线程 Thread t1 = new Thread(DoRun1); t1.Start(); //可以通过修改Thread的IsBackground,将其变为后台线程 Thread t2 = new Thread(DoRun2) { IsBackground = true }; t2.Start(); Console.WriteLine("主线程结束"); } static void DoRun1() { Thread.Sleep(500); Console.WriteLine("这是前台线程调用"); } static void DoRun2() { Thread.Sleep(1500); Console.WriteLine("这是后台线程调用"); } } }
运行上面的代码,可以看到DoRun2方法的打印信息“这是后台线程调用”将不会被显示出来,因为应用程序执行完主线程和前台线程后,就自动退出了,所有的后台线程将被自动终止。这里后台线程设置了等待1.5s,假如这个后台线程比前台线程或主线程提前执行完毕,对应的信息“这是后台线程调用”将可以被成功打印出来。
Task
.NET 4.0推出了新一代的多线程模型Task。async/await特性是与Task紧密相关的,所以在了解async/await前必须充分了解Task的使用。这里将以一个简单的Demo来看一下Task的使用,同时与Thread的创建方式做一下对比。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; namespace TestApp { class Program { static void Main(string[] args) { Console.WriteLine("主线程启动"); //.NET 4.5引入了Task.Run静态方法来启动一个线程 Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("Task1启动"); }); //Task启动的是后台线程,假如要在主线程中等待后台线程执行完毕,可以调用Wait方法 Task task = Task.Run(() => { Thread.Sleep(500); Console.WriteLine("Task2启动"); }); task.Wait(); Console.WriteLine("主线程结束"); } } }
首先,必须明确一点是Task启动的线程是后台线程,不过可以通过在Main方法中调用task.Wait()方法,使应用程序等待task执行完毕。Task与Thread的一个重要区分点是:Task底层是使用线程池的,而Thread每次实例化都会创建一个新的线程。这里可以通过这段代码做一次验证:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; namespace TestApp { class Program { static void DoRun1() { Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId); } static void DoRun2() { Thread.Sleep(50); Console.WriteLine("Task调用Thread Id =" + Thread.CurrentThread.ManagedThreadId); } static void Main(string[] args) { for (int i = 0; i < 50; i++) { new Thread(DoRun1).Start(); } for (int i = 0; i < 50; i++) { Task.Run(() => { DoRun2(); }); } //让应用程序不立即退出 Console.Read(); } } }
运行代码,可以看到DoRun1()方法每次的Thread Id都是不同的,而DoRun2()方法的Thread Id是重复出现的。我们知道线程的创建和销毁是一个开销比较大的操作,Task.Run()每次执行将不会立即创建一个新线程,而是到CLR线程池查看是否有空闲的线程,有的话就取一个线程处理这个请求,处理完请求后再把线程放回线程池,这个线程也不会立即撤销,而是设置为空闲状态,可供线程池再次调度,从而减少开销。
Task<TResult>
Task<TResult>是Task的泛型版本,这两个之间的最大不同是Task<TResult>可以有一个返回值,看一下代码应该一目了然:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; namespace TestApp { class Program { static void Main(string[] args) { Console.WriteLine("主线程开始"); Task task = Task.Run(() => { Thread.Sleep(1000); return Thread.CurrentThread.ManagedThreadId.ToString(); }); Console.WriteLine(task.Result); Console.WriteLine("主线程结束"); } } }
Task<TResult>的实例对象有一个Result属性,当在Main方法中调用task.Result的时候,将等待task执行完毕并得到返回值,这里的效果跟调用task.Wait()是一样的,只是多了一个返回值。
async/await 特性
经过前面的铺垫,终于迎来了这篇文章的主角async/await,还是先通过代码来感受一下这两个特性的使用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; namespace TestApp { class Program { static void Main(string[] args) { Console.WriteLine("-------主线程启动-------"); Task task = GetLengthAsync(); Console.WriteLine("Main方法做其他事情"); Console.WriteLine("Task返回的值" + task.Result); Console.WriteLine("-------主线程结束-------"); } static async Task GetLengthAsync() { Console.WriteLine("GetLengthAsync Start"); string str = await GetStringAsync(); Console.WriteLine("GetLengthAsync End"); return str.Length; } static Task GetStringAsync() { return Task.Run(() => { Thread.Sleep(2000); return "finished"; }); } } }
首先来看一下async关键字。async用来修饰方法,表明这个方法是异步的,声明的方法的返回类型必须为:void或Task或Task<TResult>。返回类型为Task的异步方法中无需使用return返回值,而返回类型为Task<TResult>的异步方法中必须使用return返回一个TResult的值,如上述Demo中的异步方法返回一个int。而返回类型可为void,则是为了和事件处理程序兼容,比如下面的示例:
public Form1() { InitializeComponent(); btnDo.Click += Down; } public async void Down(object sender, EventArgs e) { btnDo.Enabled = false; string str = await Run(); labText.Text = str; btnDo.Enabled = true; } public Task Run() { return Task.Run(() => { Thread.Sleep(5000); return DateTime.Now.ToString(); }); }
再来看一下await关键字。await必须用来修饰Task或Task<TResult>,而且只能出现在已经用async关键字修饰的异步方法中。
通常情况下,async/await必须成对出现才有意义,假如一个方法声明为async,但却没有使用await关键字,则这个方法在执行的时候就被当作同步方法,这时编译器也会抛出警告提示async修饰的方法中没有使用await,将被作为同步方法使用。了解了关键字async\await的特点后,我们来看一下上述Demo在控制台会输入什么吧。
输出的结果已经很明确地告诉我们整个执行流程了。GetLengthAsync异步方法刚开始是同步执行的,所以"GetLengthAsync Start"字符串会被打印出来,直到遇到第一个await关键字,真正的异步任务GetStringAsync开始执行,await相当于起到一个标记/唤醒点的作用,同时将控制权放回给Main方法,"Main方法做其他事情"字符串会被打印出来。之后由于Main方法需要访问到task.Result,所以就会等待异步方法GetLengthAsync的执行,而GetLengthAsync又等待GetStringAsync的执行,一旦GetStringAsync执行完毕,就会回到await GetStringAsync这个点上执行往下执行,这时"GetLengthAsync End"字符串就会被打印出来。
当然,我们也可以使用下面的方法完成上面控制台的输出。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; namespace TestApp { class Program { static void Main(string[] args) { Console.WriteLine("-------主线程启动-------"); Task task = GetLengthAsync(); Console.WriteLine("Main方法做其他事情"); Console.WriteLine("Task返回的值" + task.Result); Console.WriteLine("-------主线程结束-------"); } static Task GetLengthAsync() { Console.WriteLine("GetLengthAsync Start"); Task task = Task.Run(() => { string str = GetStringAsync().Result; Console.WriteLine("GetLengthAsync End"); return str.Length; }); return task; } static Task GetStringAsync() { return Task.Run(() => { Thread.Sleep(2000); return "finished"; }); } } }
对比两种方法,是不是async\await关键字的原理其实就是通过使用一个线程完成异步调用吗?答案是否定的。async关键字表明可以在方法内部使用await关键字,方法在执行到await前都是同步执行的,运行到await处就会挂起,并返回到Main方法中,直到await标记的Task执行完毕,才唤醒回到await点上,继续向下执行。更深入点的介绍可以查看文章末尾的参考文献。
async/await 实际应用
微软已经对一些基础类库的方法提供了异步实现,接下来将实现一个例子来介绍一下async/await的实际应用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; using System.Threading; using System.Threading.Tasks; using System.Net; namespace TestApp { class Program { static void Main(string[] args) { Console.WriteLine("开始获取博客园首页字符数量"); Task task1 = CountCharsAsync("http://www.cnblogs.com"); Console.WriteLine("开始获取百度首页字符数量"); Task task2 = CountCharsAsync("http://www.baidu.com"); Console.WriteLine("Main方法中做其他事情"); Console.WriteLine("博客园:" + task1.Result); Console.WriteLine("百度:" + task2.Result); } static async Task CountCharsAsync(string url) { WebClient wc = new WebClient(); string result = await wc.DownloadStringTaskAsync(new Uri(url)); return result.Length; } } }
参考文献:<IIIustrated C# 2012> 关于async/await的FAQ 《深入理解C#》
海鲜大部分是冷冻包装产品,小部分是散装称重产品,与超市类似,应选择“商超版”,除了钱箱、扫描枪,还应接电子秤。
触摸屏
不用记键盘快捷键,商品少的话直接点选,连扫码、输码、搜索都省了
好用的收银软件
见下方表格
称重一体
散装商品方便取重
Windows 7 及以上版本 或 安卓 操作系统
安心连网,用于支付宝/微信收款,方便连锁店共享数据。选择 Windows 的话建议选到 win10,因为 win7 将在 2020 年停止支持;新的收银机基本用的安卓,可能因为各种成本低吧,不过听说安卓收银机会卡顿,类似于安卓手机的操作感,核心数和内存跟PC也不是一个概念。
固态硬盘
Windows 建议选固态,开机快;安卓是闪存
销售过程中任何时间使用会员卡,而不是必须先扫会员卡,再扫商品
标签打印机,支持打印价格签(不干胶热敏纸条码),称重商品需要贴上即时生成的条码
支持扫描枪或扫码器扫描客户手机上的支付宝、微信(动态)付款码,以规避客户使用支付成功的截图来欺骗。需要一些配置,提现扣手续费。
支持拼音简码销售
选购步骤 先选择适合自己的收银软件,再选择配置和外观,当然要考虑外接设备的兼容性(电子秤同步称重、软件开钱箱、是否需要标签打印机或后厨打印机、扫描枪是否需要支持支付宝微信 等等)。
注:标签打印机不同于小票打印机,前者用于打印临时标签,可以包含名称、价格、重量、条码等信息,贴于散装称重商品,需选购;后者打印小票给顾客提供购买商品的明细,一般收银机自带。
附:几大收银软件功能对比(从商超的角度分析)注:部分功能可能因配置不同而不同,具体应咨询客服。
二维火 | 来钱快 | 美团收银 | |
版本 | 餐饮版 商超版 奶茶版:适用连锁店 | 基础版:适用餐饮 零售版:适用超市 专业版:适用连锁餐厅 | |
操作系统 | 安卓 | 安卓 | 安卓 |
适配触摸屏 | √ | √ | √ |
扫描商品条码、支付二维码 | √ | √ | √ |
对接外卖平台 | 美团外卖、饿了么、百度外卖 | 美团外卖、饿了么 | 美团外卖 |
手机下单 | √ | 免费微店、客户自助点餐 | 收银机点餐、顾客扫码点餐、服务员点餐 |
收银方式 | 聚合支付、支付宝、微信、现金 | 现金、支付宝、微信、银联、优惠券组合付款 | 现金、支付宝、微信、优惠券、会员、记账 |
会员功能 | 会员等级、积分、折扣、微信公众号营销 | 会员等级、充值、积分、折扣、俏销短信、报表 | 短信、储值、积分 |
支持手机 | 火掌柜App | 来钱快App 收银助手 | 美团管理APP |
报表 | √ | √ | √ |
自制条码(接标签打印机) | 商超版、奶茶版支持 | ||
盘点库存 | √ | 手机操作 | 电脑端 |
对接电子秤 | √ | 商超版支持 | |
连锁店管理 | √ | √ | 专业版支持 |
其它特点 | 排队叫号; 自主微信公众号粉丝运营; 小程序点餐 | 免费微信店铺,推广公众号 | 提高美团和大众点评店铺人气; 排队软件; 一店多收银台; |
售价 | 买收银机赠(零售 488 元),免费升级,连锁版每用户 599 元 | 零售版和基础版免费(买收银机赠),专业版收费 | |
相关链接 | 来钱快: 杭州萨宝科技: 软件和驱动: | 官方网站: 视频教程: http://shouyin.meituan.com/productGuide | |
我的评价 | 界面拟物还不错,具体没有深究 | 公司没有美团有名,但是入行比美团早,产品成熟,创新力强 | 可能更适合于奶茶店类型,对打包、外卖完美适用,有机会试用的话可以给出更客观的评价 |
本文资料整理于 2018 年 7 月
舟山海鲜捕鱼人品牌诚招代理,电话:13646674565(微信同号)

在开发微信中的网页时,会遇到一些域名相关的配置:
① 公众号设置 - 功能设置 - 业务域名
② 公众号设置 - 功能设置 - JS接口安全域名
③ 接口权限 - 网页授权获取用户基本信息
④ 商户平台 - 产品中心 - 开发配置 - JSAPI支付授权目录
⑤ 小程序 - 开发 - 开发设置 - 业务域名
⑥ 公众号开发 - 基本设置 - IP白名单
第①种 业务域名:相对不重要,只是用来禁止显示“防欺诈盗号,请勿支付或输入qq密码”提示框,可配置 3 个二级或二级以上域名(个人理解是“非顶级域名”,即填写了 b.a.com 的话,对 c.b.a.com 不起作用,待测)。
我们网站的域名和公众号是没有绑定关系的,那么你在打开一个(可能是朋友分享的)网页时,跟哪个公众号的配置去关联呢,答案是 JS-SDK。
测试结果:由于一个月只有3次修改机会,这次先测二级域名,有效;再测顶级域名,有效;删除所有,仍有效。所以应该是缓存作用。过几天再试,然后下个月先测顶级域名,来确定直接填写顶级域名是否对所有二级域名有效。
第②种 JS接口安全域名:是配置所配置的域名下的网页可调用 JS-SDK。可配置 5 个一级或一级以上域名(个人理解是“任何级域名”,即填写了 b.a.com 对 c.b.a.com 也有效,但对 c.z.a.com 无效,待测。如果我们拥有顶级域名对应网站的控制权(上传验证文件到网站根目录),直接填写顶级域名即可)。
使用 JS-SDK 的每个网页都必须注入配置信息(wx.config),而之前必须获取 jsapi_ticket,jsapi_ticket api 的调用次数非常有限,必须全局缓存。而获取 jsapi_ticket 之前必须先获取 access_token,同样需要全局缓存。所以,我们专门做个接口,功能是传入需要使用 JS-SDK 的网页的 url,输出 wx.config 需要用到的配置信息,来实现在不同网页(网站)使用 JS-SDK。
第③种 网页授权域名:这是已认证的服务号才能享有的特权,主要作用是获取用户在该服务号中的 openid 和 unionid。可配置 1 个 2 个回调域名(可填写任意级别的域名,但仅对该域名的网页(网站)有效,若填写了 a.com 对 b.a.com 是无效的)。
因此,如果我们需要在不同二级域名甚至不同顶级域名下的网页(以下称之为活动页面)实现用户授权,需要做一个统一的代理授权页面(回调域名当然是填写这个页面所在的域名),引导用户依次打开:微信授权页面 - 代理授权页面 - 活动页面,根据开发说明文档,具体实现如下:
当用户第一次打开活动页面时,引导打开微信授权页面(https://open.weixin.qq.com/connect/oauth2/authorize),其中参数 redirect_uri 指定回调地址,即代理授权页面地址,参数 state 指定活动页面地址。微信授权页面返回 code 和 state,code 作为换取网页授权 access_token 的票据。到这一步,本来可以由代理授权页面直接拿这个 code 去换取 access_token、openid 和 unionid 了,但是由于当前用户还在 302 重定向过程中,将这些信息带入到活动页面时势必导致信息泄露,所以这里将 code 追加到 state 指定的网址上后重定向到活动页面,活动页面拿到 code 再通过服务器端向代理授权页面所在服务器请求 openid 和 unionid,并将它们保存于 Session 中视为用户登录。这样,服务号的 appid 和 secret 也能得到保护。代理授权页面请求的微信服务器接口地址是 https://api.weixin.qq.com/sns/oauth2/access_token。
注:网页授权 access_token 不同于 JS-SDK 中使用的全局唯一接口调用凭据 access_token,没有请求次数限制。
流程既然通了,实现逻辑可以这样设定:
活动页面首先判断 Session 中是否有 openid 或 unionid,若有表示已授权登录;没有再判断地址栏是否有 code 参数,若有则调用代理授权页面所在服务器的接口,用 code 换 openid 和 unionid;没有则直接重定向到代理授权页面,带上 state。用 code 换 openid 和 unionid 时若成功则保存至 Session,若失败则仍然重定向到代理授权页面,带上 state,特别注意 state 中的活动页面地址确保没有 code 参数。
第④种 JSAPI支付授权目录:涉及到微信支付时用到,顾名思义是固定某一个网站内的某个目录,以“/”结尾。最多可添加 5 个。如果支付页面在目录 https://www.a.com/b/ 下,那么可以填写 https://www.a.com/b/ 或 https://www.a.com/(建议后者),暂未测试填写 https://a.com/ 会不会起作用。涉及支付安全,建议设置支付页面的最深一层不可写的目录,以防目录内被上传后门文件带来的安全隐患。
第⑤种 小程序业务域名:任何需要在小程序的 web-view 组件中打开的网页,都必须配置小程序业务域名,限制 20 个。该域名要求必须 https,可填入“任何级域名”(建议填顶级域名,即填写了 a.com 对 b.a.com 也有效。如果我们拥有顶级域名对应网站的控制权(上传验证文件到网站根目录),直接填写顶级域名即可)。
第⑥种 IP白名单:仅填写管理全局 access_token 的中控服务器的 IP。
总结:在上述自定义接口部署完成后,如果微信中的网页想获取用户的 unionid,则不需要配置域名,直接使用统一的代理授权即可;如果需要使用 JS-SDK 功能,如分享、上传等等,则需要配置 JS 接口安全域名;如果有表单,最好配置一下业务域名。
本文系个人经验总结,部分结果未经证实,欢迎指正!QQ:940534113

编者按:本文作者 Nick Babich 在文中介绍了几种 “提高” 加载速度的方法。
当我们设计产品的时候,我们没有办法模拟不同的加载速度。因此如果用户等待太长的时间才能看到内容,并不是我们特意的安排。
网速不稳定,尤其是当我们加载图片或音乐时,时间会较长。在这种情况下,我们不得不考虑在这种间隙向用户展示什么内容才能让他们感觉不枯燥。
加载动图(Spinner)效果不佳
加载 Spinner 并不是暗示加载或思考的正确方式。默认加载图标(例如 iOS 的加载动画效果是从中心点辐射的灰色线条)通常具有消极的含义。它们应用于多种操作系统功能之中,包括设备启动、连接到网络或者加载数据。
人们讨厌只看到加载 Spinner,但是却看不多进度或时间。让用户盯着一个下载进度条或者旋转圈会让跳出率提高。
不确定的等待时间比已知的、有限的等待时间让人觉得更长。你应该给你的用户一个清晰地等待时间。
进度条可以告诉用户这个过程需要花费多长时间,但是一般不太正确。你可以通过一些方法隐藏过程中的延迟,例如你可以在开始的时候让速度显示地快一点,在结尾的时候,显示速度慢一点。进度条不应该中断,否则用户就会认为这个 App 卡住了。
后台操作
在后台操作中包含行为有两个优点——用户可见;在用户真正发出请求时就会加载完毕。当程序在后台运营时,给用户呈现一些其他的内容。一个很好的案例是在 Instagram 中加载图片。用户一旦选择想要分享的图片,就开始加载。
在后台加载图片的过程中,Instagram 邀请用户添加标题和标签,当用户准备按 “分享” 键时,加载过程就完成了,这时候就可以立刻分享图片了。
仿真内容和 Placeholder(占位符)
如果你无法缩短加载时间,那么你应该试图让用户在等待中更高兴一点。可以利用这个时间显示一些临时的信息。为了提高用户的参与度,可以使用仿真内容作为文本和图片。
几点小建议:
1、加载屏幕不应该太亮。不需要太吸引眼球。Facebook 的灰色 Placeholder 就是一个很好的例子。当加载内容时使用模板元素,让用户熟悉将要加载的内容的整体结构。
2、如果要加载图片,你可以在 placeholder 中使用加载图片的主色调。Medium 的图片加载效果比较好。首先加载一个小型的模糊图片,然后转化成一个清晰的大图片。
使用 placeholder 和仿真内容并没有加快加载过程,但是在用户眼中加载速度好像变快了。
分散用户的注意力
为了不让用户在等待时感到枯燥,可以适当分散他们的注意力。你可以使用一些有趣的、始料未及的东西吸引用户的注意力,为 App 加载赢得充足的时间。
动画片可以分散访客的注意力,让他们忽略加载时间。
结论
用户讨厌等待,如果你让用户觉得他们没有等待,那么他们就会喜欢你的 App。一定要让用户觉得 App 的加载时间比他预计的短。
本文适用于 IIS 7, IIS 7.5, IIS 8, IIS 8.5, IIS 10 等 Web 服务器,IIS 6(Windows Server 2003)用户请查阅 ISAPI_Rewrite。
在 IIS 中要实现 URL 重写,需要下载并安装 URL Rewrite 组件,http://www.iis.net/downloads/microsoft/url-rewrite
在 IIS 管理器中选中任意网站,主窗口可见“URL 重写”,双击打开。(如果你想配置这台服务器的所有网站有效,直接选中左侧菜单中的服务器名,打开“URL 重写”即可。)
右侧“添加规则...”,选择“入站规则”中的“空白规则”,确定。
填写规则名称,在“匹配 URL”框中选择“与模式匹配”,根据自己的需求选择“正则表达式”、“通配符”或“完全匹配”,“模式”中填写要防盗链的文件路径规则,例如正则表达式 ^.*\.(jpg|png)$ 将匹配所有目录下的 .jpg 和 .png 文件。
接下来将设置图片在允许的域名下显示。
在“条件”框中选择“全部匹配”,点击“添加”,“条件输入”中填写“{HTTP_REFERER}”(不含引号,含花括号),表示判断 HTTP 请求中 Header 的 Referer。选择“与模式不匹配”,模式中填写匹配规则,如 ^$ 表示允许 Referer 为空(如直接从浏览器打开的情况),再加一个规则 ^https?://([^/]*\.)?(xoyozo.net|himiao.com)/.*$ 表示允许在 xoyozo.net 和 himiao.com 这两个域名下显示图片。当然如果你有很多域名或需要设置不同的规则,可以继续添加,但最好把访问量大的规则移到前面,从而减少系统匹配次数,提高访问效率。
最后,在“操作”框中设置你想要的处理方式,可以是“重定向”到一张防盗链提醒的图片上(推荐类型临时 307),也可以自定义响应,例如,状态代码(403),子代码(0),原因(Forbidden: Access is denied.),描述(You do not have permission to view this directory or page using the credentials that you supplied.),查看 HTTP 状态代码。
如果你是配置某个网站的“URL 重写”,那么在网站根目录下的 web.config 文件中,<system.webServer /> 节点下可以看到刚刚配置的规则,例如:
<rewrite> <rules> <rule name="RequestBlockingRule1" stopProcessing="true"> <match url="^.*\.(jpg|png)$" /> <conditions> <add input="{HTTP_REFERER}" pattern="^https?://([^/]*\.)?(xoyozo.net|himiao.com)/.*$" negate="true" /> <add input="{HTTP_REFERER}" pattern="^$" negate="true" /> </conditions> <action type="Redirect" url="http://42.96.165.253/logo2013.png" redirectType="Temporary" /> </rule> </rules> </rewrite>

在同一内网,如果不同服务器上的项目间通过接口调用数据,那么可以通过更改 hosts 的方法来提高访问速度,降低带宽使用。
上述情况一般地容易想到直接使用 IP 形式的网址来调用数据,如果这样的话,接口方必须将项目建立在 Web 服务器的默认网站上,在有多个项目共存的服务器上,这种方式就有非常大的局限性。而通过更改 hosts 文件,我们可以直接使用域名形式的网址来调用数据,该域名将会被“解析”到内网 IP 上,而且是映射到绑定了该域名的网站上(绑定时“IP 地址”设为“全部未分配”)。
具体实现方法:
Windows Server:用记事本打开文件 C:\Windows\System32\drivers\etc\hosts
Linux / centos:vi /etc/hosts
添加一行:接口服务器的内网 IP + 空格 + 接口网站的域名
如:64.233.162.84 www.google.com

软件名称 | 价格 | 软件介绍 |
---|---|---|
ProPresenter | 试用 / $399 | 一款跨平台(Mac、Windows),专为高品质现场(包括晚会、体育赛事、会议等)打造字幕及多媒体展示的软件。 (试用版是全功能的,但输出窗口有水印,试用期两周) |
Sports Sounds Pro | 免费 / $149.95 | 一款专业用于现场事件的音控软件。 (免费版是全功能的,仅有一些限制,比如:只能播放 10 组中每组的前 3 页的第 1 行,而且只能放置 180 个按钮) |
Miro Video Converter | 免费 | 可以导出兼容 HTML5 网页播放的视频格式(.mp4)。 |
Vistumbler | 免费 | 无线网络扫描工具。 |
VNC | 免费 / $30 / $40 | Mac 上优秀的远程桌面软件。 |
免费 | 快速扫描目录大小和空间占用 | |
IconWorkshop | 试用 / 购买 | 优秀的 ICO、ICON 制作软件,专业图标制作,编辑,转换工具 |
$19 / $59 | 功能强大的数字音乐编辑器,是一个集声音编辑、播放、录制和转换的音频工具。 | |
EasyRecovery | EasyRecovery 是由全球著名数据厂商 Kroll Ontrack 出品的一款数据文件恢复软件。支持恢复不同存储介质数据:硬盘、光盘、U盘、移动硬盘、数码相机、手机、Raid 文件恢复等,能恢复包括文档、表格、图片、音视频等各种文件。 | |
DiskGenius | 一款专业级的数据恢复软件,算法精湛、功能强大!支持多种情况下的文件丢失、分区丢失恢复;支持文件预览;支持扇区编辑、RAID 恢复等高级数据恢复功能。 | |
sagethumbs | 免费 | 预览 PSD 文件 |
WebP Codec for Windows | 免费 | 预览 WebP 文件 |
ventoy | 免费 | 多系统启动U盘解决方案 |
