博客 (74)

原标题:关于 PHP 获取 IP 地址的几种方法


PHP 获取客户端的 IP 地址有 4 种方式:

  1. REMOTE_ADDR:浏览当前页面的用户计算机的 IP 地址

  2. HTTP_X_FORWARDED_FOR:记录代理信息,会把每一层代理都记录

  3. HTTP_CLIENT_IP:客户端的 IP

  4. X-Real-IP:没有标准,由上一跳决定


REMOTE_ADDR 一般是不能伪造的,因为是通过服务器与客户端握手协议来获取的。而 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP 是在 header 信息里面,所以客户端是可以进行很轻松的伪造。下面是对这三种方式详解:

https://www.v2ex.com/t/230367

https://www.test404.com/post-1448.html

https://www.cnblogs.com/mypath/articles/5239687.html


一、关于 REMOTE_ADDR
这个变量获取到的是“直接来源”的 IP 地址,所谓“直接来源”指的是直接请求该地址的客户端 IP 。这个 IP 在单服务器的情况下,很准确的是客户端 IP ,无法伪造。当然并不是所有的程序都一定是单服务器,比如在采用负载均衡的情况(比如采用 haproxy 或者 nginx 进行负载均衡),这个 IP 就是转发机器的 IP ,因为过程是客户端 -> 负载均衡 -> 服务端。是由负载均衡直接访问的服务端而不是客户端。


二、关于 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP
基于“一”,在负载均衡的情况下直接使用 REMOTE_ADDR 是无法获取客户端 IP 的,这就是一个问题,必须解决。于是就衍生出了负载均衡端将客户端 IP 加入到 HEAD 中发送给服务端,让服务端可以获取到客户端的真实 IP 。当然也就产生了各位所说的伪造,毕竟 HEAD 除了协议里固定的那几个数据,其他数据都是可自定义的。


三、为何网上找到获取客户端 IP 的代码都要依次获取 HTTP_CLIENT_IP 、 HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR
基于“一”和“二”以及对程序通用性的考虑,所以才这样做。 假设你在程序里直接写死了 REMOTE_ADDR ,有一天你们的程序需要做负载均衡了,那么你有得改了。当然如果你想这么做也行,看个人爱好和应用场景。也可以封装一个只有 REMOTE_ADDR 的方法,等到需要的时候改这一个方法就行了。


X_FORWARDED_FOR 与 X-Real-IP 的区别:

X_FORWARDED_FOR:记录了所有链路里的代理 IP 值,比如下面所说的,经过了 3 次代理,分别是 1.1.1.1, 2.2.2.2, 3.3.3.3,其中 1.1.1.1 是客户端 IP,2.2.2.2 是代理服务器,接下来同理。

X-Real-IP:是只会记录前一次代理的 IP 地址。

一般来说,X-Forwarded-For是用于记录代理信息的,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加在X-Forwarded-For

来自4.4.4.4的一个请求,header 包含这样一行

X-Forwarded-For: 1.1.1.1, 2.2.2.2, 3.3.3.3

代表请求由1.1.1.1发出,经过三层代理,第一层是2.2.2.2,第二层是3.3.3.3,而本次请求的来源IP4.4.4.4是第三层代理

X-Real-IP,没有相关标准,上面的例子,如果配置了X-Read-IP,可能会有两种情况

// 最后一跳是正向代理,可能会保留真实客户端IP
X-Real-IP: 1.1.1.1
// 最后一跳是反向代理,比如Nginx,一般会是与之直接连接的客户端IP
X-Real-IP: 3.3.3.3

所以 ,如果只有一层代理,这两个头的值就是一样的。

那一般在后端取值(比如 node.js 通过 nginx 代理)是用哪个值呢?我看 sf 上看一般推荐是用 X-Forwarded-For,直接用 X-Real-IP 岂不是更方便点?

X-Forwarded-For 确实是一般的做法

  1. 他在正向(如 squid)反向(如 nginx)代理中都是标准用法,而正向代理中是没有 x-real-ip 相关的标准的,也就是说,如果用户访问你的 nginx 反向代理之前,还经过了一层正向代理,你即使在 nginx 中配置了 x-real-ip,取到的也只是正向代理的 IP 而不是客户端真实 IP

  2. 大部分 nginx 反向代理配置文章中都没有推荐加上 x-real-ip ,而只有 x-forwarded-for,因此更通用的做法自然是取 x-forwarded-for

  3. 多级代理很少见,只有一级代理的情况下二者是等效的

  4. 如果有多级代理,x-forwarded-for 效果是大于 x-real-ip 的,可以记录完整的代理链路


1、将以下代码保存为 Client.php

// php 脚本开始
$ch = curl_init();
$url = "http://localhost/ser.php";
$header = array('CLIENT-IP:208.165.188.175', 'X-FORWARDED-FOR:208.165.188.175');
// 声明伪造 head 请求头
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
$page_content = curl_exec($ch); curl_close($ch);
echo $page_content;


2、将以下代码保存为 ser.php

// php 脚本开始
echo getenv('HTTP_CLIENT_IP');
echo getenv('HTTP_X_FORWARDED_FOR');
echo getenv('REMOTE_ADDR');


测试结果为

208.165.188.175
208.165.188.175
127.0.0.1


上面结果可看出,http_client_ip、http_x_forwarded_for 都被伪造了,而 remote_addr 还是127.0.0.1 就是客户端 IP

总结:

如果我们没用到负载均衡(CDN)的话直接用 REMOTE_ADDR 获取 IP。

如果使用了一级 CDN 的话,CDN 会把 REMOTE_ADDR 转发成 X-Real-IP,我们服务器可以获取 X-Real-IP 来获取 IP 值。如果是多级 CDN 的话需要我们来做 nginx 代理,详细:https://www.cnblogs.com/princessd8251/articles/6268943.html

就是第一台负载服务器获取 REMOTE_ADDR 转发成 X-Real-IP,之后的去继承前一台的 X-Real-IP 就可以了,这里记住必须是去继承,不然第二台会把第一台的 REMOTE_ADDR 转发成 X-Real-IP 导致错误。

在 discuz! 中的获取 IP 的方法:

private function _get_client_ip() {
    $ip = $_SERVER['REMOTE_ADDR'];
    if (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']) AND preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
        foreach ($matches[0] AS $xip) {
            if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
                $ip = $xip;
                break;
            }
        }
    }
    return $ip;
}

这里 DZ 为了符合有些用户会用代理,所以才首先使用了两个容易伪造的方法,如果有需要可以自行修改。

h
转自 hykeda 5 年前
6,496

这是一篇可能解决困扰了 .NET 程序猿多年的文章!

首先,使用 Visual Studio 2019 创建一个 ASP.NET WEB 应用程序,直接选用了 MVC 模板。

直接发布项目,默认的设置如下图:

image.png

对于小型项目,按默认设置发布基本可满足正常运行,首次运行打开第一个页面基本在 5~6 秒(视服务器配置),其它页面的首次打开也基本在 1~2 秒完成,非首次瞬间打开。

一旦项目功能变得复杂,文件增多,会导致发布后首次运行打开第一个页面 30 秒以上,其它页面的首次打开 10 秒左右,非首次瞬间打开。

这是因为项目在发布时没有进行预编译,而是在用户访问网页时动态编译,一旦应用程序池回收,或项目文件改动,都会重新编译,再次经历缓慢的“第一次”,这是不能忍的。

于是咱们来研究一下“预编译”。

在发布页面勾选“在发布期间预编译”,这时发布会在“输出”窗口显示正在执行编译命令(编译时间会比较长):

image.png

该选项对发布后的文件结构和内容影响不大,因此对首次执行效率的提升也不大,重要的在后面。

在“高级预编译设置”窗口中:

image.png

我们针对预编译选项和合并选项分别做测试。

不勾选“允许更新预编译站点”,会致 bin 目录中生成许多 .compiled 文件,而所有 .cshtml 文件的内容都是:

这是预编译工具生成的标记文件,不应删除!

如果是 Web From 网站,.aspx/.ashx 等文件内容同上。

尝试打开网站页面,你会发现,除了项目启动后的第一个页面仍然需要 1~2 秒(无 EF),其余每个页面的首次都是瞬间打开的(EF 的首次慢不在本文讨论范围)。这让我对预编译有一种相见恨晚的感觉!

这里偷偷地告诉你,把 Views 目录删掉也不影响网页正常打开哦~为什么不让删,咱也不敢问,咱也不敢删。

目的达到了,有一些后遗症需要解决,比如 bin 目录内杂乱无章。

选“不合并。为每个页面和控件创建单独的程序集”,结果是 bin 多出许多 App_Web_*.dll 文件。

选“将所有输出合并到单个程序集”,填写程序集名称。这时会发现“输出”窗口执行了命令:

image.png

如果程序集名称跟已有名称冲突,会发生错误:

合并程序集时出错: ILMerge.Merge: The target assembly '******' lists itself as an external reference.

查看 bin 目录,.compiled 文件还在,但 App_Web_*.dll 合并成了一个程序集。FTP 的“不合并”也是把所有 App_Web_*.dll 上传一遍,所以不存在相对于“合并”的增量发布优势。

是不是勾了“视为库组件删除(AppCode.compiled 文件)”.compiled 文件就会不见?意外之外,情理之中,bin 没有什么变化。

继续选择“将各个文件夹输出合并到其自己的程序集”,呃,bin 中文件数不降反增。

最后选择“将所有页和控件输出合并到单个程序集”,同样程序集名称不能冲突。结局令人失望,bin 中仍然一大堆 .compiled 和 App_Web_*.dll。


整理成表格:

1
允许更新预编译站点

aspnet_compiler.exe -v / -p \Source -u \TempBuildDir 

重复发布后 bin 目录文件数:不会增多(页面不进行预编译)

2

不允许更新预编译站点,不合并

aspnet_compiler.exe -v / -p \Source \TempBuildDir 

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

3

不允许更新预编译站点,不合并。为每个页面和控件创建单独的程序集

aspnet_compiler.exe -v / -p \Source -c -fixednames \TempBuildDir 

重复发布后 bin 目录文件数:不会增多(编译后的文件名固定,FTP 方式的部分 App_Web_*.dll 文件可能实现增量上传)

4

不允许更新预编译站点,将所有输出合并到单个程序集,不勾选“视为库组件”

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -o 程序集名称 -copyattrs AssemblyInfo.dll -a

重复发布后 bin 目录文件数:不会增多(.compiled 固定名称,App_Web_*.dll 合并为一个)

5

不允许更新预编译站点,将所有输出合并到单个程序集,勾选“视为库组件”

aspnet_compiler.exe -v / -p \Source \TempBuildDir 

aspnet_merge.exe \TempBuildDir -o 程序集名称 -copyattrs AssemblyInfo.dll -a -r 

重复发布后 bin 目录文件数:不会增多(.compiled 固定名称,App_Web_*.dll 合并为一个)

6

不允许更新预编译站点,将每个文件夹输出合并到其自己的程序集,前缀

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -prefix 前缀 -copyattrs AssemblyInfo.dll -a  

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

7

不允许更新预编译站点,将所有页和控件输出合并到单个程序集

aspnet_compiler.exe -v / -p \Source -c \TempBuildDir 

aspnet_merge.exe \TempBuildDir -w 程序集名称 -copyattrs AssemblyInfo.dll -a  

重复发布后 bin 目录文件数:.compiled 不会增多,App_Web_*.dll 增多

bin 目录下,页面的程序集文件(App_Web_*.dll)增多的原因是编译后的文件名不固定,发布到会导致残留许多无用的程序集文件。

相比较,如果第 3 种能实现 FTP 稳定的增量上传的话是比较完美的(还有一个缺点是:如果页面有删除,目标 bin 内对应该页面的 .compiled 和 .dll 不会删除,这跟“允许更新预编译站点”是一个情况),那么第 4 种 或第 5 种也是不错的选择(同样有缺点:执行合并比较慢)。

测试一个有 300 个页面的项目,compiler 用时约 2 分钟,merge 用时约 5 分钟,发布用时约 4 分钟。

这里有个槽点,执行预编译和合并是佛系的,CPU 和磁盘使用率永远保持在最低水平。

所以如果是要经常修改的项目,那么建议选择“不合并”的第 3 种发布方式:

微信图片_20190715160035.png

“视为库组件(删除 AppCode.compiled 文件)”:移除主代码程序集(App_Code 文件夹中的代码)的 .compiled 文件。 如果应用程序包含对主代码程序集的显式类型引用,则不要使用此选项。


补充:

  • 不允许更新预编译站点发布后,因为前端页面没有内容,因此无法单独修改发布(单独发布一个页面后,在访问时不会生效!),只能全站发布,耗时较长;bin 目录有变动将导致使用 InProc 方式存储的 Session 丢失。

  • 预编译的另一个优点是可以检查 .aspx / .cshtml 页面 C# 部分的错误(特别是命名空间和路径引用)。

  • 改为预编译发布后,可以将服务器上残留的 .master / .ascx / .asax 删除,但不能删除 .aspx / .ashx /.config 等。

  • VS 发布到 FTP 经常会遗漏一些页面文件,不合并时会遗漏独立文件,合并后也会遗漏合并后的 .dll 的文件,合并的好处就是方便检查是否完全上传发布。

  • 慎选“在发布前删除所有现有文件”!一旦勾选发布,世界就清静了,所有网友上传的图片附件以及网站运行产生的其它文件,消失得无影无踪。不管发布到文件系统还是发布到 FTP 都一样。当然,如果是先发布到文件系统,再通过 FileZilla 等 FTP 软件上传到服务器的,建议勾选此项。

  • .NET Core 应用程序部署:https://docs.microsoft.com/zh-cn/dotnet/core/deploying/index

  • 由于上传文件时 bin 目录文件较多,理论上 bin 目录内的文件有任何改动都会重启应用池,而且 VS 是单线程上传的,导致期间网站访问缓慢,服务器 CPU 升高,我的做法是:发布到文件系统,再使用专用 FTP 工具上传,上传用时约半分钟(如果大小不同或源文件较新则覆盖文件)。还嫌慢?那就打包上传,解压覆盖。

  • 关于本文研究对象的官方解释:高级预编译设置对话框

  • 出现“未能加载文件或程序集“***”或它的某一个依赖项。试图加载格式不正确的程序。”的问题时,先用改用 Debug 方式发布会报详细错误,一般是 .aspx 等客户端页面有 C# 语法问题,注意提示报错的是 /obj/ 目录下的克隆文件,应更改原文件。排除错误后关闭所有页面,再使用 Release 方式发布。

xoyozo 6 年前
11,070

前提:

若需获取用户 unionid,则小程序必须已绑定到微信开放平台。


  1. 小程序调用 wx.login(),将 code 发送到开发者服务器

  2. 开发者服务器请求微信接口 code2Session,获得 session_keyopenid,有机会获得 unionid参 UnionID 机制说明)。因此无需任何用户授权即可获取 openid

  3. 访问须要已获取用户信息的页面时,可通过小程序端使用 button + getUserInfo 的方式请求用户授权

  4. 访问须要已获取手机号码的页面时,可通过小程序端使用 button + getPhoneNumber 的方式请求用户授权

  5. code2session、getUserInfo、getPhoneNumber 等接口返回数据存入数据库 dt_weapp_user

  6. 服务端的任何接口均返回口令状态包(含自定义会话口令等信息),小程序端应保存于 storage

  7. 请求 getUserInfo 后应判断 detail.errMsg 是否为 getUserInfo:ok,请求 getPhoneNumber 后应判断 detail.errMsg 是否为 getPhoneNumber:ok

  8. 授权窗口的弹出情况此文

  9. 口令状态包是用来传递到客户端用来标识用户唯一凭证的,包含字段:会话口令(自定义用户凭证)、会话口令有效时间(秒)、是否已获取 unionid 或昵称(视业务需求)、是否已获取手机号码uid(可选),以及其他用来标识业务身份字段。服务端可根据会话口令从数据库中获取该用户的所有已知信息。

    一般情况下,当已获取手机号码时,uid 必有值,否则,uid 必为空。因此 uid 不是必须传递到客户端的。

    通过 code2Session 获得的 session_key、以及 openidunionid手机号码等机密信息不允许包含在口令状态包中并缓存在客户端,客户端需要用到手机号码时单独调用接口获取。

  10. 若业务不要求以手机号码作为用户唯一标识,那么口令状态包中不需要包含是否已获取手机号码,仅 uid 即可。在客户端访问须要业务用户登录的页面时,也仅判断 uid 有值即可。


流程图:


微信小程序授权登录获取 unionid、用户信息流程.png


为更好地适应 2017.7.19 发布的《小程序内用户帐号登录规范调整和优化建议》开发者服务器提供的所有业务逻辑接口的返回值中都应包含口令状态包,约定有以下相关的返回值和处理动作(返回值按个人喜好来定):

口令状态接口返回ASP.NET Web API 语句处理动作
access_token 空或失效401 状态码return Unauthorized();login() + code2Session,获取 openid,生成 access_token
access_token 有效,但未获取 uniond 或用户信息401 状态码,http 头 WWW-Authenticate 中标注 getUserInforeturn Unauthorized(new AuthenticationHeaderValue("getUserInfo"));getUserInfo()
access_token 有效,但未获取手机号码(即未找到业务用户)401 状态码,http 头 WWW-Authenticate 中标注 getPhoneNumberreturn Unauthorized(new AuthenticationHeaderValue("getPhoneNumber"));getPhoneNumber()
xoyozo 6 年前
8,629
  1. 首先,手机打开【设置】-【更多设置】-【关于手机】-【版本信息】,触摸“软件版本号”7次。

  2. 返回【更多设置】底部出现【开发者选项】,打开后开启【USB 调试】。

  3. 使用数据线连接手机和电脑(注意必须使用数据线,而非一般充电宝附带的充电线,虽然插头类型是一样的),弹出“允许 USB 调试吗?”对话框,选择“确定”。

  4. 电脑上安装 vivo 手机助手,就可以管理手机了。手机端可以安装手机助手

  5. 如果需要连接 HBuilderX 进行安卓应用调试,需要从手机顶部下划,将“USB已连接”中的“管理文件”更改为“传输照片”。并使用 vivo 手机助手手动安装调试基座(控制台中会提示)。


xoyozo 6 年前
17,989

Dark Mode 亦称为 暗黑模式、黑暗模式、暗色模式、黑夜模式、深夜模式、夜间模式 等,以下介绍几种常用软件的 Dark Mode 的设置方法。


iOS:

【iOS 13+】在 设置 - 显示与亮度 - 选择“深色”

【iOS 11+】在 设置 - 通用 - 辅助功能 - 显示调节 - 反转颜色 中开启“智能反转”。

“智能反转”缺点:第三方应用上显示的图片会以“经典反转”的方式展示。


Android:

设置 - 显示 - 主题模式,选择“暗色主题”

版本支持:Android 9.0 - Pie(Android P)


macOS:

系统偏好设置 - 通用 - 外观,低版本系统中勾选“使用暗色菜单栏和 Dock”,高版本系统中直接点击预览图选择主题。

版本支持:在 OS X Yosemite 10.10 中提供支持,在 macOS Mojave 10.14 中全新升级。


Windows:

桌面右键“个性化”(或从 Windows 设置中打开),在“颜色”选项卡,选择默认应用模式“暗”。

版本支持:Windows 10 October 2018 Update(版本 1809)


Microsoft Office:

文件 - 选项 - 常规 - Office 主题:黑色

在一个组件中设置后(如 Word),会在其它的组件中同时生效(如 Excel)。但 Visio 没有“黑色”主题(至少在 2019 中),我尝试更改为“深灰色”,Word 也变为“深灰色”,然后在未关闭 Visio 的情况下再次更改 Word 为“黑色”,Visio 界面竟然也变成了“黑色”,设置选项中为空白。

版本支持:Office 2016


Adobe Photoshop:

点开 菜单:编辑 - 首选项 - 界面,根据自已喜爱更改颜色方案。

版本支持:Photoshop CS6(可能更早),新版中已默认启用


CorelDRAW:

点开菜单:工具 - 选项,左侧展开 工作区 - 外观,主题选择“暗”或“黑体”。

版本支持:CorelDRAW X8(可能更早)


Microsoft Visual Studio:

点开菜单:工具 - 选项 即可更改颜色主题为“深色”(左侧选项卡为 环境-常规)。 

版本支持:Visual Studio 2012


微信开发者工具:

点开菜单:设置 - 外观设置,选择“深色主题”

仅在文件代码面板有效


Microsoft Edge:

设置 - 自定义 - 选择一个模式 - 暗


Chrome:

在 Chrome 74 版本中支持。

其开发者工具(F12)早在 50 版本中已提供 Dark 主题,在开发者工具右上角展开竖状三点图标 - Settings - Theme: Dark

Windows 的 Chrome 的 Dark 模式无需设置,会根据 Windows 自身是否为暗模式来调整。

因其 Dark 模式不容易区分当前标签页,如需禁用 Dark 模式,参此文


Adobe Acrobat Reader DC:

点开菜单:视图 - 显示主题 - 深灰


HBuilder X:

点开菜单:工具 - 主题 - 酷黑


Code Write:

设置 - Editor - Theme - Dark(默认已启用)

xoyozo 6 年前
11,628

本文不定时更新中……

收集了一些在开发过程中遇到的一些问题的解决方法,适合新手。


异常:

出现脚本错误或者未正确调用 Page()

原因:不小心删了第一行内容:<template>


异常:

模块编译失败:TypeError: Cannot read property 'for' of undefined

at fixDefaultIterator (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4277:24)

at mark (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4306:5)

at markComponent (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4371:5)

at baseCompile (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4384:15)

at compile (D:\HBuilderX\plugins\uniapp\lib\mpvue-template-compiler\build.js:4089:28)

at Object.module.exports (D:\HBuilderX\plugins\uniapp\lib\mpvue-loader\lib\template-compiler\index.js:43:18)

原因:新建的页面(简单模板)只有以下 3 个标签,须在 <template /> 中添加一些代码,如 <view />

<template>
</template>

<script>
</script>

<style>
</style>

异常:

模块编译失败:TypeError: Cannot read property 'toString' of undefined

at Object.preprocess (D:\HBuilderX\plugins\uniapp\lib\preprocess\lib\preprocess.js:56:15)

at Object.module.exports (D:\HBuilderX\plugins\uniapp\lib\preprocessor-loader.js:9:25)

原因:没有原因,纯抽风,HX 关掉再开就好了。


异常:

Cannot set property 'xxx' of undefined;at pages/... onLoad function;at api request success callback function

原因:属性未定义,例如 

data() {
	return {
		item: { }
	}
}

而直接赋值 this.item.abc.xxx = '123';

解决:

data() {
	return {
		item: {
			abc: ''
		}
	}
}

问:page 页面怎样修改 tabBar?

答:官方文档未给出答案,百度了一圈也无果(2018-10-23),但有人说小程序的 setTabBarBadge() 方法设置角标是可以用的。


坑:

VM1694:1 获取 wx.getUserInfo 接口后续将不再出现授权弹窗,请注意升级

参考文档: https://developers.weixin.qq.com/community/develop/doc/0000a26e1aca6012e896a517556c01

填坑:放弃使用 uni.getUserInfo 接口来获取用户信息,uni.login 可返回用于换取 openid / unionid 的 code,参:uni.login、 code2Session


坑:字符搜索(当前目录)(Ctrl+Alt+F)搜不出所有结果

填坑:顾名思义他只搜索当前目录,即当前打开文件所在目录,而非我误认为的整个项目根目录。在“项目管理器”中选中要搜索字符的目录即可。


坑:uni.navigateTo() 或 uni.redirectTo() 没反应

填坑:这两个方法不允许跳转到 tabbar 页面,用 uni.switchTab() 代替。


坑:使用“Ctrl+/”快捷键弹出“QQ五笔小字典”窗口

解决:打开QQ五笔“属性设置”,切换到“快捷键设置”选项卡,把“五笔小字典”前的勾取消(即使该组合键是设置为Ctrl+?)。


坑:<rich-text /> 中的 <img /> 太大,超出屏幕宽度

填坑:用正则表达式给 <img /> 加上最大宽度

data.data.Content = data.data.Content.replace(/\<img/gi, '<img style="max-width:100%;height:auto" ');

坑:无法重命名或删除目录或文件

填坑一:“以管理员身份运行”HBuilder X 后再试。

填坑二:关闭微信开发者工具、各种手机和模拟器后再试。

填坑三:打开“任务管理器”,结束所有“node.exe”进程后再试。


坑:

 thirdScriptError 
 sdk uncaught third Error 
 (intermediate value).$mount is not a function 
 TypeError: (intermediate value).$mount is not a function
Page[pages/xxxx/xxxx] not found. May be caused by: 1. Forgot to add page route in app.json. 2. Invoking Page() in async task.
Page is not constructed because it is not found.

填坑:关闭微信开发者工具、各种手机和模拟器后,删除“unpackage”目录。


坑:

Unexpected end of JSON input;at "pages/news/view" page lifeCycleMethod onLoad function
SyntaxError: Unexpected end of JSON input

填坑:给 uni.navigateTo() 的 url 传参时,如果简单地将对象序列化 JSON.stringify(item),那么如果内容中包含“=”等 url 特殊字符,就会发生在接收页面 onLoad() 中无法获取到完整的 json 对象,发生异常。

uni.navigateTo({
	url: "../news/view?item=" + JSON.stringify(item)
})

所以应该把参数值编码:

uni.navigateTo({
	url: "../news/view?item=" + escape(JSON.stringify(item))
})

如果是一般的 web 服务器来接收,那么会自动对参数进行解码,但 uni-app 不会,如果直接使用:

onLoad(e) {
	this.item = JSON.parse(e.item);
}

会发生异常:

Unexpected token % in JSON at position 0;at "pages/news/view" page lifeCycleMethod onLoad function
SyntaxError: Unexpected token % in JSON at position 0

需要解码一次:

onLoad(e) {
	this.item = JSON.parse(unescape(e.item));
}

需要注意的是,unescape(undefined) 会变成 'undefined',如果要判断是否 undefined,应是 unescape 之前。


坑:图片变形

填坑:mode="widthFix"


坑:页面如何向 tabBar 传参

填坑:全局或缓存


坑:编译为 H5 后,出现:Access-Control-Allow-Origin

填坑:参阅


坑:编译为 H5 后,GET 请求的 URL 中出现“?&”

填坑 :客户端只求 DCloud 官方能够尽快修复这个 bug,IIS 端可以暂时用 URL 重写来防止报 400 错误,参此文


坑:[system] errorHandler TypeError: Cannot read property 'forEach' of undefined

填坑:待填


xoyozo 6 年前
17,702

原文标题:新手还在学习排版配色,高手已经在做内容设计了…

任何事物的呈现和传达都需要通过一定的媒介,在媒介承载的过程中,均会产生损耗。我们设计的目的之一就是将所传达的内容在媒介承载的过程中让损耗降到最低,呈现出我们想要给受众的东西,且能够被快速察觉、理解和获取(主动及被动的)。

文本作为语言沟通的书面化,一直以来承载着大量的信息,也是生活中最常见及熟知的方式。

当前人们快节奏的生活状态、快消的阅读习惯以及注意力分散,所以需要我们通过设计手段来减少视觉、心理及认知压力,让用户能够快速定位、理解和消化。同样,我们也需要根据目标、任务甚至品牌的诉求,从而更好的服务于主题。

以下是工作中一些心得和总结,旨在从更多角度去思考和完善,让文本信息能够得到更好的呈现和传达。

一、前提

前提是做事的先要条件。

  • 达成目标

  • 了解受众

  • 具体情景

二、目的

目的是做这件事的动力。

  • 满足用户所需,帮助完成工作;

  • 简单直接,有效传达;

  • 达成一致,统一规范可实施。

三、角度

角度是考虑要做的内容。

  • 准确性

  • 一致性

  • 易读性

  • 内容调性

1. 准确性

秉持文本信息准确明了、简达明意,无歧义

首先要明确所传达的群体对象,尽量避免使用行话,使用「用户」能直接理解的文本信息,当然相应的专业词汇也应给予良好的解释和说明。

案列:我们将 「循环次数」 更改成 「轮播次数」 ,「循环次数」会让人产生思考(循环一次是播放一次还是两次的),而 「轮播次数」 就显得更加直观明了且更符合上下文的语境。

用词完整、阐述直接

用词完整,例如保存修改,而不是简化为保存;阐述直接,避免模棱两可,模糊不清。

内容传达上应做的良好的「自解释」

例如:涉及操作事件的文本命名应根据上下文准确的进行表达,而不是含糊其辞的,使文本能够准确的解释和表达将要发生的事件及行为。

寻找更加合适的表达方式

例如:未输入提示,「XXX不能为空」 和 「请输入XXX」,第一个在表达上其实有一些责怪,而第二个表达同样说明了意思,但在口吻上却更加温和,并告诉用户应该怎样操作和行动。

避免错别字

错别字只会拉低产品的品质和用户内心的形象,请务必严格检查。避免把 「登录」 写成 「登陆」。

准确应用标点符号

标点符号能够赋予文字节奏,表达语气以及对内容的组织。准确应用,能够帮助文字更加有效传达和被人理解。

2. 一致性

同一事物用词一致,消除重复

例如,涉及新建的操作,一会用「新建」,一会又用「新增」、「创建」或者「添加」;涉及称谓,一会用「你」,一会又用「您」、「我」或者「我的」;涉及帮助,一会用「支持」,一会用「帮助」或者「服务」等等,我们应该消除这些重复,统一用词。

相似场景、意思和语境下句式表述一致

例如,未输入提示,应避免「请输入XXX」和「XXX不能为空」等不同的表达方式。

标点符号规范

根据符号使用规范并结合自身产品情况具体定义。例如:全角和半角,如常见「:」和「:」,截断省略「…」等等。又如:标题,提示文本不加结束符号等。

时间表达规范

时间是一个记录戳,需要根据与当前进行定义,显示不同的格式。

例如:今天发生的(自0时起),显示时分(24h);今天之前发生的,显示月-日(例如02-12);跨年,显示年-月-日(例如2017-12-30)。

数字使用规范

例如:统计数据统一使用阿拉伯数字。

大小写使用规范

专有名词大小写,单位符号等。例如:iOS

中西文混排规范

中英文之间需要加空格等。

代称一致

第一人称「我」,第二人称「你」和「您」,具体根据场景进行使用,同场景统一一致。你和您请不要随意混用或均使用,应当统一。

操作名称与目的页面标题一致

常见于移动端,在 PC 常见于链接及导航。

3. 易读性

简化内容,避免啰嗦

简单而直接,避免长段使用短语,保持措辞简洁,让读者感受到阅读乐趣,引诱他们深入阅读。

打破复杂冗长

通过段落、有序列表(项目编号)、无序列表等方式使内容结构化,便于视觉扫描。

  • 段落:根据句意,进行分段呈现。

  • 有序:当项目顺序或优先级重要(程序等)时,使用编号列表。

  • 无序:项目相关时使用项目符号列表,但顺序或优先级无关紧要。

  • 结构化:节奏和韵律。例如,电话号码或者银行卡号,使用连字符或空格使其容易被读取和识别。

重要内容突出显示

让用户首先看到最重要的内容,而不是去寻找它们。

经过良好的排版

合理使用文字大小:使用合理的字体大小,太小太大对于屏幕阅读来说都是低效率的。网页端字体大小一般使用不低于12px,更加直观易辨(对于多数人而言)的字体14px和16px;移动端字体大小不小于10pt(sp),12-18pt(sp)都是常用的字体选择范围。

颜色与对比度:颜色我们需要考虑色彩本身(色相、明度和饱和度)给人直观感受和文化寓意的,以及文本与背景之间是否有足够的对比度,从而方便人们可以更加直观舒服的进行阅读。W3C 建议的视觉呈现文本和文本的图像具有对比度至少为4.5:1,大型文字和图像的对比度至少为3:1,具体详情可了解 Contrast (Minimum):Understanding SC 1.4.3

字间距:汉字属于方块字,原则上文字外框彼此紧贴配置,称作密排;在各字之间加入固定量的空白来排列文字,称作疏排;减少字距,使得文字外框一部分重叠,称作紧排。文字排版时,会根据具体情况对字间距进行调整。大多时候我们对采用疏排方式,增加字间距,以提高易读性。

行高:具有良好的行距的文本,更易阅读和引导用户视线。与行之间的空白称为行距,文字尺寸+行距=行高,行距一般介于文字尺寸的50%–100%之间,自然行高的设置一般为文字尺寸的1.5-2倍。文字尺寸较小时,行高设定也会相对较小。行距一般不会超过文字尺寸,因为这样并不会因此而增加易读性。

段间距:段落与段落之间的距离,段间距大于行间距,行间距一般设置为文字大小的2-3倍之间,合适的段间距能够缓解用户的视线压力,起到很好的节奏及阅读定位。

行字数:一行的文字数量。一行文本过长,用户需要去移动脖子或视角,易造成的眼睛疲惫感,造成阅读困难;此外,在大段文本中找到正确的行也将变得困难。过短视线需要不断换行,从而打断了读者阅读节奏,造成尴尬的断裂效果;行太短也会造成用户在一行没读完的情况下去关注和阅读下一行。

虽然至今汉字依然没有正统的方法和具体行字数来衡量文本的完美长度,个人经验在12px下30-60汉字左右(包含标点),具体也要根据内容、人群等约束和变量,当然最重要的是要相信你自己(专业的设计师)的眼睛和判断。

词语尽量避免同行断开:例如,行末为「跳」,下行开头为「转」,读起来就有断句的存在感。

对齐方式:中文(简体)排版一般遵循左对齐的原则,符合我们从左到右的阅读习惯。文字居中,本身不适合可读性,但可用于许多小段文本块。右对齐在表格设置中,可用于数字的对比等应用。

符号避头尾:中文中行首遇到不能置于行首的标点符号,必须要将移动到前一行行尾。

合理突出:对于关键字、要点通过位置、加粗、比例大小和色彩处理等,以便让用户直接关注到。当然也要控制突出数量,毕竟都是「重点就没有重点」,过多也会扰乱和分散用户的注意力。

链接:链接文本需要很好的说明用户将要去何处,可以使用蓝色或者下划线标示出链接的样式,这是用户熟悉方式。神奇的「下划线」为体验赋能

尽量少用斜体:PC 和无线端的各个官方的中文字体包并没有斜体预设,生拉硬扯的倾斜在一定程度上是影响美观度,并造成一定的阅读困难。如果是为了突出或区别可以考虑使用字重、大小和颜色等方式。

层级处理:有对比就有层级关系,可通过大小、字重、色彩、距离、方向、纹理、形状、背景等等方式,可以让整体排版布局更加富有层次结构,让内容的可读性得到明显的提升。 例如:标题、副标题、引用和内容也是一种层级处理(结合了大小、色彩或者距离等等)。

留白:合适的留白可以更好的烘托内容主题,缓解视觉压力。

数量信息前后有汉字时需加空格:不加空格会出现前后拥挤的视感,另一方面可凸显数字信息。

4. 内容调性

依据产品定位,通过文本表述传递其相应的价值观和情感诉求

任何产品都有所针对的人群及自身的品牌形象。C端产品和 B端产品,儿童产品和成年人产品,所使用的语言表达方式自然也都是不一样的。

依据不同状态和用户群体

根据状态(正面、中性和负面)和用户(新手、中级用户和专家),使用合理的语调及用词规范,以适应不同的情境和状况。

始终坚持积极主动的,而不是消极令人沮丧

「请输入内容」与「错误,内容不能为空」,同样的意思却有不同的感受,从积极的一面表达就是传播正能量。

四、通用产出物

  • 字体

  • 日期和数字

  • 标点符号

  • 大小写

  • 中英文混排

  • 代称

1. 字体

字族 Font-Family

Font-Family 属性设置的字体系列。Font-Family 属性设置多个字体作为一种「后背」机制,浏览器不支持第一种字体,它会尝试下一个字体。

如果字体系列的名称超过一个字,它必须用引号,如Font-Family:「宋体」。

对于依附在 PC 端产品而言,统一的字体规范,以保证在不同平台、不同浏览器下保持良好的美观性和易读性。

以下呈现的是 Ant Design 的字体家族。个人在使用了多款后,觉得最好的一份:

font-family:「Chinese Quote」, -apple-system, BlinkMacSystemFont, 「Segoe UI」, 「PingFang SC」, 「Hiragino Sans GB」, 「Microsoft YaHei」, 「Helvetica Neue」, Helvetica, Arial, sans-serif,「Apple Color Emoji」, 「Segoe UI Emoji」, 「Segoe UI Symbol」;

如果大家想了解字体排列前后顺序的玄机可以认真看《推荐!Web中文字体应用指南》这篇文章。

以下备注区域,是我在使用字族的路上磕磕碰碰所收集到的有限知识,也算知其所以然了,若有不妥、错误和缺漏欢迎指正。

备注区域:

-apple-system:macOS 和 iOS平台的 Safari 调用 SanFrancisco 字体

BlinkMacSystemFont:macOS Chrome 调用 SanFrancisco 字体

Roboto字体,由 Google 开发,是 Android 4.0「Ice Cream Sandwich」及后面Android版本的默认字体。

Segoe UI 取代Tahoma,Windows 从 Vista 开始的界面默认西文字体。利用 ClearType 技术的新字体 Segoe UI 看起来比现在略显僵硬的 Tahoma 更加人性化。

Tahoma 被采用为 Windows 2000、Windows XP、Windows Server 2003及 Sega 游戏主机 Dreamcast 等系统的默认字型。

Arial 是一套随同多套微软应用软件所分发的无衬线体 TrueType字型。

Microsoft YaHei 微软雅黑,该字体将作为 Windows Vista 的默认字体取代2001年推出的 XP系统下默认的宋体汉字,以支持高清显示的 ClearType 功能。

Simsun 宋体,一直是简体中文版 Windows XP系统及之前版本的默认字体。但由于字体的特性,在Windows Vista 中已经改用支持 OpenType 的微软雅黑,

HanHei SC 威锋瀚黑,现苹果简体中文,OS X 10.11 El Capitan 开始,

STHeiti 华文黑体,分为「黑体-简(Heiti SC)」和「黑体-繁(Heiti TC)」,OS X 10.6 Snow Leopard 直至 OS X 10.10 Yosemite。

Hiragino Sans GB 冬青黑体

STXihei 华文细黑,是苹果公司 Mac OS X9 以及之前版本的操作系统的中文默认字体,截至 OS X 10.5 Leopard。

PingFang SC 为 iOS9.0 以后系统自带中文字体。

SanFrancisco iOS9 正式发布之后,替换了之前的 Helvetica Neue 成为了 iPhone/iPad 系列设备的默认字体。

Myriad Set Pro 苹果向 adobe 公司定制了一款西文字体,是以 myriad 为原型的,完成后在市面上叫做「myriad set」,后期升级为「myriad set pro」。

Helvetica Neue 意为「新 Helvetica」

Helvetica 是苹果电脑的默认西文字体

sans-serif 并非一个具体字体,而是css的通用字体族,具体是什么字体是由浏览器设置决定的。

字号 font-size

标题,内容,注释说明等不同字号的大小。

字间距 letter-spacing

根据不同字号,及文本数量进行字间距定义。

行高 line-height

设置行高能很好的解决,缓和上下文本之间拥挤在一起的情况。

颜色 text-color

这里主要讲下注意对比度的问题,很多产品在这一点上都忽视了这一点,搞出了所谓的「小清新」。

2. 日期和数字

日期

使用完整数字日期,如:2018-01-02。

时间

  • 使用24小时制,如 13:01:29

  • 具体到时分秒,如当前对话显示 09:01:02

  • 使用半角 「:」

  • 日期和时间之间包含一个空格,如 2018-09-01 13:01:20。

数字

使用阿拉伯数字。

对四位或更多位数的数字使用逗号。

对手机号码使用前后无空格的连字符「-」。不要使用点,空格等其他符号。

数字范围使用前后无空格的连字符「-」。

正负数后不加空格。

数字和字符之间不需要空格

货币

人民币符号(¥)在数字前面,精确到小数点后两位。

测量单位

储存单位(B、kB、MB、GB、TB),在数量和度量单位之间包含一个空格。

对于长度「毫米(mm)、厘米(cm)、分米(dm)、千米(km)、米(m)、微米(μm)、纳米(nm)等」和重量「千克(kg)、克(g)、毫克(mg)、微克(ug)等」等测量单位应为小写(电流单位除外)。在数量和度量单位之间包含一个空格。

屏幕单位「像素(px)、逻辑分辨率(pt、dp、sp)、英寸(in)等 」应为小写。在数量和度量单位之间包含一个空格。

在连续列出尺寸时,将度量单位放在末尾,而不是在每个数字之后,并包括一个空格。

在所有情况下,数字和单位之间包含一个空格。HTML代码的最小空间是 & hairsp; 或 & #8202;

测量单位分为基本单位和导出单位。国际单位制共有7个基本单位长度:

长度:米 m;

质量:千克(公斤) kg;

时间:秒 s;

电流:安[培] A;

热力学温度:开[尔文] k;

物质的量:摩[尔] mol;

发光强度:坎[德拉]cd;

并由物理关系导出的单位称「导出单位」 。

3. 标点符号

省略不必要的标点

标题、副标题、输入框下的提示文本、输入框占位符、悬停提示中的文本、Toast中、弹窗等短句,在遣词造句时尽量避免标点符号,始终末尾不要使用句点。

有序列表和无序列表

使用冒号引入项目列表,列表后不使用标点。

使用列表来表示步骤、组或信息集。简要介绍列表的上下文。在顺序重要时列出数字列表,比如当您描述流程的步骤时。当列表的顺序不重要时,不要使用数字。

常用标点符号规范

  • 空格:链接与前后文本之间增加空格;数字和单位之间包含一个空格;电话号码与前后文本包含一个空格;

  • 省略号「…」:半角省略号,超出截断代替省略文本;

  • 星号「*」:半角星号。表单必填、说明备注;

  • 连接号「-」:半角连接号,前后无空格,如2018-01-04,2008-2018;

  • 冒号「:」:半角冒号,用于时间的表示,如16:45 ;

  • 冒号「:」:全角冒号,用于表单;

  • 破折号「——」:中文破折号占两个汉字空间;

  • 书名号「《》」:产品中常用于法律条文。

相关推荐:

4. 大小写

专门名词大小写

文件格式

当一般引用文件扩展名类型时,全部大写而不包含句点。

  • GIF

  • PDF

  • HTML

  • JPG 格式

引用特定文件时,文件名应该是小写的:

  • 内容策略-设计完全手册.pdf

  • 皮皮虾.gif

  • 西湖.jpg

  • hot.html

5. 中西文混排

中英文之间需要加空格

中文与数字之间需要加空格

中文为主,使用全角符号且与英文或数字之间不加空格

6. 代称

为了表达双方的平等,避免使用「您」。使用「你」代称客户/用户,借以表达客户的口吻。在客户/用户为主的情况下使用「我」。避免同一句子中混用「你」和「我」。

对于「您」还是「你」的使用并非绝对,主要看行业以及服务的对象

在《胜于言传-Web内容创作与设计的艺术》中作者建议:

当用户提问的时候:

  • 在问题中使用「我」和「我的」(用户的声音)

  • 在答案中使用「你」和「你的」(应用对用户说话)

  • 用「我们」和「我们的」代表回答公司

当应用提问的时候:

  • 在问题中使用「你」和「你的」(应用向用户提问)

  • 在答案中使用「我」和「我的」(用户的声音)

  • 用「我们」和「我们的」代表回答公司

五、指导建议

  • 操作行动

  • 文本说明

  • 句式结构

  • 语音和语调

  • 写作建议

1. 操作行动

按钮

清晰可预测。应该能够预测当点击按钮时会发生什么。

行动号召。按钮应始终带有强烈的动词,鼓励行动。为了给用户提供足够的上下文,在按钮上使用 {动词} + {名词} 格式,除了保存,关闭,取消或确定等常用操作。

以下是常用词的含义,以避免不恰当或混淆使用:

所有具体的用词需结合场景和生活习惯。

链接

使用描述性的链接文本。切勿使用「点击这里」或「这里」作为链接文本。

如果一个链接出现在句子的末尾或逗号之前,不要链接标点符号。

链接使用蓝色,这是用户习以为常的认知,并明确区分点击和未点击的区别。

2. 文本说明

对操作说明,功能说明,名词(术语)解释,提示信息等进行用户测试,是否明白其意,记住这是一个不断优化的过程。

以下是产品内的主要文本:

  • 操作文本:按钮;

  • 导航文本:全局和局部导航、目录、链接;

  • 说明文本:功能说明、术语解释;

  • 提示文本:弹框、toasts、操作反馈、系统反馈、通知等;

  • 操作说明:功能引导说明,操作文档;

  • 标题和副标题:弹框标题、操作说明标题、法律条款标题等;

  • 条款:法律条款、申明;

  • ALT:为图片添加文字说明。

3. 句式结构

通用场景下的语句可进行归纳在一起,形成统一的句式结构。

例如:

操作反馈:成功直接提示结果,失败显示结果+说明原因+如何解决。

二次确认:先说明利害,再询问是否操作。

标题:「动词」+ 「名词」格式等。

4. 语音和语气

这听起来是谁,什么样的语音和语气能代表我们,我们想传达什么的形象。

因此,你可以建立一套准则,一般而言准则应该:

  • 基于产品当前的业务;

  • 准则可被执行,避免过于空洞;

  • 易于记忆,3-5个尚可;

  • 并随着产品发展和愿景的变化而不断适应改进。

例如:

积极主动

始终坚持积极主动的,而不是消极令人沮丧。

自信专业

避免听起来傲慢、亲密、孩子气或其他不适当的或非正式的。

友好尊重

依据不同状态(正面、中性和负面)和用户群体(新手、中级用户和专家),使用合理的语气及用词规范。

5. 写作建议

个人写作过程中的一些小感悟:

  • 好的结果是不断修改来的,修改的基础是要先写下来,所有先记录而不是停留在脑子里,这才是一切开始的基础。

  • 记住用户很忙且没有耐性,甚至不聪明,这会不断的促使你修改调整。

  • 找人阅读并呈现结果,并询问其含义和建议。这是检验的最佳实践。

  • 过段时间再来看看,或许有更好的方式。

结尾

这并非是一个完整的(内容层面可能保存图片风格,插画图标等),还有很多地方可以补充。重要的是找到适合你的产品,并有这样的意识去不断优化你的产品内容,从而更好的服务你的用户。

W
转自 Wiiii 6 年前
3,980

〓 系统

功能命令--help示例
关机halt
halt
重启reboot
reboot
系统监视器top系统时间, 运行天数, 当前登录用户数, 系统负载
总进程数, 运行中的, 睡眠的, 停止的, 未响应的
Cpu(s):us 用户, sy 系统, ni XX, id 空闲, wa 等待, hi XX, si XX
Mem, 已使用, 空余, 缓冲
Swap, 已使用, 空余, 缓冲
快捷键:
M 按占内存排序
P 按占Cpu排序
1 显示每个 Cpu
k 杀死进程
q 退出
top
查看进程psaux
-ef
列出包含 java 的进程
ps aux |grep java 
ps -ef |grep java
查看内存及 Swap 用量free-b,-k,-m,-g 按单位显示free -m
查看系统时间date   显示 CST 时间
-R 显示时区
-u 显示 UTC 时间
date
查看硬件时间clock
clock
设置系统日期

date -s 月/日/年
设置系统时间

date -s 时:分:秒
将系统时间写入到硬件时间

clock -w
查看系统版本

cat /etc/*release
升级系统软件

yum update -y

〓 文件

功能命令--help示例
进入目录cd
cd .. # 上一层目录
cd /root # 根目录
列出目录ls白色:表示普通文件
蓝色:表示目录
绿色:表示可执行文件
红色:表示压缩文件
浅蓝色:链接文件
红色闪烁:表示链接的文件有问题
黄色:表示设备文件
灰色:表示其他文件
ls
创建目录mkdir
mkdir XXX
删除目录rm
rm -rf XXX
删除文件rm
rm XXX
复制文件cp
cp XXX YYY
复制目录cp-r 复制目录及目录内的所有项目
-v 详细显示进行的步骤
cp -rv XXX YYY
重命名文件mv-i: 若指定目录已有同名文件,则先询问是否覆盖旧文件;
-f: 在mv操作要覆盖某已有的目标文件时不给任何指示;
mv 源文件 目标文件
移动文件mvmv 一个或多个文件 目标目录
下载文件wget下载到当前目录wget http://XXX.tar.gz
计算文件/目录的磁盘用量du-a 不仅显示目录,同时显示文件
-h 容易阅读方式显示
--max-depth=N 可指定计算深度
du -ah --max-depth=1 | sort -n
查找文件find
find /home -name *.apk

〓 tar

功能命令--help示例
tartar-z 是否压缩
-c 打包
-x 解包
-v 详细地列出处理的文件
-f 
打包:tar -cvf abc.tar abc
解包:tar -xvf abc.tar
压缩打包:tar -zcvf abc.tar.gz abc
解压解包:tar -zxvf abc.tar.gz

〓 磁盘

功能命令--help示例
查看所有磁盘及分区fdisk -l
fdisk -l
查看当前挂载df-h 按可阅读的方式打印数值和单位
-T 显示文件系统类型
df -hT
管理磁盘分区fdisk /dev/***进入后的操作说明:
m 显示命令菜单
d 删除一个分区
n 创建一个分区(e 扩展分区;p 主分区)
t 改变分区ID
q 不保存退出
w 保存退出
fdisk /dev/vdb
格式化分区mkfs.*** /dev/***N
mkfs.xfs /dev/vdb1
挂载分区mount /dev/***N /***
mount /dev/vdb1 /www
卸载分区umount /dev/***N
umount /dev/vdb1
开机自动挂载vi /etc/fstab配置文档格式:设备 挂载点 文件系统类型 defaults 0 0打开:vi /etc/fstab
配置:/dev/vdb1 /www xfs defaults 0 0

〓 网络

功能命令--help示例
查看 IP 配置ifconfig
ifconfig
配置网卡 IP
配置文件目录:/etc/sysconfig/network-scripts/
配置文件格式:
DEVICE=eth0 / eth0:0 / ... # 在配置多线时若使用 cp 命令复制配置文件,必须修改此项以防止冲突
HWADDR=XX:XX:XX:XX:XX:XX # 网卡地址
TYPE=Ethernet # 以太网
UUID=********
ONBOOT=yes # 开机启动
NM_CONTROLLED=yes
BOOTPROTO=static # 使用静态 IP
IPADDR=192.168.1.2 # IP 地址
NETMASK=255.255.255.XXX # 子网掩码
GATEWAY=192.168.1.1 # 网关
DNS1=114.114.114.114
DNS2=8.8.8.8
vi ifcfg-XXXN(:N)
重启网卡
使配置生效service network restart

〓 防火墙

功能命令--help示例
配置 iptables
添加需要允许的端口的方法同 22 端口vi /etc/sysconfig/iptables
重启使配置生效

service iptables restart

〓 用户/权限

功能命令--help示例
添加用户useradd-g 组名 # 加入到该组
-s /bin/false #不允用户直接登录系统
useradd –g 组名 用户名 -s /bin/false
修改密码passwd
passwd 用户
查看所有用户

cut -d : -f 1 /etc/passwd 
查看可以登录系统的用户

cat /etc/passwd | grep -v /sbin/nologin | cut -d : -f 1
删除用户
-r, --remove                  remove home directory and mail spooluserdel 用户
添加用户组groupadd
groupadd 组名
为组添加用户(用户必须已存在)gpasswd
gpasswd -a 用户 组
将用户移出组gpasswd
gpasswd -d 用户 组
查看用户所属组groups
groups 用户
查看组中有哪些用户groupmems
groupmems -g 组 -l
更改文件/目录所有者chown-R 递归处理所有的文件及子目录chown -R 用户:组 ***
更改文件/目录权限chmod-R 以递归方式更改所有的文件及子目录chmod -R 777 ***

〓 vi 编辑器

功能命令--help示例
打开文件vi
vi XXX
进入编辑模式
按 a/i/o/Insert 等
进入末行模式/命令模式
按 Esc后:
:w 保存不退出
:q 退出(提示是否保存)
:wq 保存并退出
:w XXX 另存到文件 XXX
:q! 不保存退出

〓 计划任务

功能命令--help示例
设置计划任务crontab详细步骤见本页底部crontab -l # 查看计划任务
crontab -e # 编辑计划任务

〓 网站

功能命令--help示例
简单审查日志cat | grep
cat 日志文件 | grep 关键词1 | grep 关键词2 | more
日志分析goaccess
见下文

〓 goaccess

功能命令--help示例
安装yum install goaccess

日志格式NCSA Commbined Log Format
date_format %d/%b/%Y
log_format %h %^[%d:%^] "%r" %s %b "%R" "%u"
参数-f需要解析的日志文件
参数-e指定 IP 地址统计
参数-p指定配置文件可以将上面的日志格式内容保存到文件 ~/.goacessrc
参数-H显示 HTTP 协议信息
参数-M显示 HTTP 方法信息
生成文件

goaccess -f 日志文件 -p ~/.goaccessrc > 目标文件.htm

〓 lnmp

功能命令--help示例
重启 LNMP

/root/lnmp restart
重启 MySQL

/etc/init.d/mysql restart
重启 PureFTPd

/root/pureftpd restart
安装 LNMP
http://lnmp.org/install.html 
常见问题
http://lnmp.org/faq.html 
状态管理命令
http://lnmp.org/faq/lnmp-status-manager.html 
相关软件目录及文件位置
http://lnmp.org/faq/lnmp-software-list.html 
防跨站、跨目录安全设置(仅支持 PHP 5.3.3 以上版本)
http://www.vpser.net/security/lnmp-cross-site-corss-dir-security.html 
查看 Nginx 版本

nginx -V
查看 MySQL 版本

mysql -V
查看 PNP 版本

php -v
查看 Apache 版本

httpd -v
查内存

cat /proc/meminfo
php.ini

vim /usr/local/php/etc/php.ini
MySQL 配置文件

vim /etc/my.cnf
添加网站

/root/vhost.sh
添加 ProFTPd 用户

/root/proftpd_vhost.sh

〓 nginx

功能命令--help示例
启动/停止/重启service nginx

/etc/rc.d/init.d/nginx

service nginx start
service nginx stop
service nginx restart
伪静态在 .conf 文件中配置
rewrite ^(.*)/read-htm-(.*)\.html(.*)$ $1/read.php?$2.html? last;
rewrite ^(.*)/thread-htm-(.*)\.html(.*)$ $1/thread.php?$2.html? last;
rewrite ^(.*)-htm-(.*)$ $1.php?$2 last;
rewrite ^(.*)/simple/([a-z0-9\_]+\.html)$ $1/simple/index.php?$2 last;
rewrite ^(.*)/data/(.*)\.(htm|php)$ 404.html last;
rewrite ^(.*)/attachment/(.*)\.(htm|php)$ 404.html last;
rewrite ^(.*)/html/(.*)\.(htm|php)$ 404.html last;
防盗链在 .conf 文件中配置HttpRefererModule location ~* \.(gif|jpg|png|swf|flv)$
{
valid_referers none blocked *.0574bbs.com *.eyuyao.com 0574bbs.com eyuyao.com;
if ($invalid_referer)
{
rewrite ^/ http://web1.eyuyao.com/yyad/src/3122.jpg;
# return 404;
}
}
浏览器缓存在 .conf 文件中配置
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}

〓 vsftpd

功能命令--help示例
安装

yum install vsftpd
查看是否已安装

rpm -q vsftpd
启动/停止/重启service vsftpd
service vsftpd start
service vsftpd stop
service vsftpd restart
配置文件

vi /etc/vsftpd/vsftpd.conf

〓 MySQL

功能命令--help示例
登录mysql
mysql -u username -p
登出

exit
查看信息

status;
查询当前正在执行的 SQL 语句

show processlist;
删除指定时间之前的日志PURGE
PURGE MASTER LOGS BEFORE '2015-1-1 0:00:00';

〓 scp 远程文件/目录传输命令 (yum install openssh-clients) 用法

scp 会把文件权限(读取/写入/执行)带过来,但所有者为当前执行 scp 命令的用户。

scp 低版本有许多漏洞,用完最好 yum remove openssh-clients

scp 采用直接覆盖的机制,如需判断文件无差异则跳过,应改用 rsync 命令。查看 rsync 详细使用方式及与 scp 对比

功能命令--help示例
若远程服务器 SSH 端口非默认scp-P 端口号
下载远程服务器上的文件到本地scp
scp 远程用户@远程服务器:远程文件 本地文件
下载远程服务器上的目录到本地scp

-P 端口

-v 显示进度

-r 递归

scp -r 远程用户@远程服务器:远程目录 本地目录

实例:scp -r root@x.x.x.x:/a/b/ /c/d/

结果:/c/d/b/,即将整个 b 复制到 d 下(注意与 rsync 命令的区别)


本地文件上传到远程服务器scp
scp 本地文件 远程用户@远程服务器:远程文件
本地目录上传到远程服务器scp最终目录结构参:远程->本地scp -r 本地目录 远程用户@远程服务器:远程目录

〓 rsync 远程文件/目录传输命令 (yum install rsync) 用法查看 rsync 详细使用方式及与 scp 对比

rsync 会把文件权限(读取/写入/执行)带过来,所有者也会带过来。

相比于 scp 最大的优势就是可以增量同步

功能命令--help示例
下载远程服务器上的目录到本地rsync

-a 递归

-v 详细

-p, -- perms 保持权限

-g, -- group 保持属组

-o, --owner 保持属主

-r 递归

--progress 打印

--delete 删除已不存在的文件

-u 表示仅更新较新的文件

-z 表示在传输过程中进行压缩

-e 'ssh -p 2222' 指定其它端口

rsync 远程用户@远程服务器:远程目录 本地目录

实例:rsync -avu --progress root@x.x.x.x:/a/b/ /c/d/

结果:/c/d/,即将 b 内的文件(夹)复制到 d 下(注意与 scp 命令的区别)


本地文件上传到远程服务器rsync
rsync 本地文件 远程用户@远程服务器:远程文件
本地目录上传到远程服务器rsync最终目录结构参:远程->本地rsync 本地目录 远程用户@远程服务器:远程目录

〓 ftp 客户端 (yum install ftp)

功能命令--help示例
登录ftp
ftp 目标服务器
列出远程当前路径目录/文件ls
ls
创建远程目录mkdir
mkdir 目录名
删除远程目录(空)rmrmdir
mkdir 目录名
进入远程目录cd
cd 目录名
显示远程当前路径pwd
pwd
重命名远程文件rename
rename 原文件名 新文件名
上传文件put
put 本地文件名
下载文件get
get 远程文件名
批量下载文件mget需要单个确认
批量下载文件【lftp】mirror参数有很多mirror
返回 shell(不退出)!
!
返回 ftp(接上步)exit
ftp

exit
ftp
结束bye
quit

bye
quit

〓 iftop

流量监控工具 教程 

〓 GoAccess

实时网站日志分析工具 官网 

〓 Cacti

网络流量监测图形分析工具 官网  百科 

常见问题笔记

加硬盘

  • 插入新硬盘

  • 若有 RAID,则先设置,使操作系统能认到硬盘

  • 使用 fdisk 命令对新设备进行分区

  • 使用 mkfs 命令对新分区进行格式化

  • 使用 mount 命令进行挂载

  • 设置开机自动挂载(vi /etc/fstab)

更改 MySQL 数据库目录位置

  • 停止 MySQL 服务

  • 将原数据目录转移或复制到新位置(若是复制,则修改所有者使原来一致)

  • 找到 my.cnf 配置文件(一般在 /etc/),修改 datadir 值为新路径

  • 启动 MySQL 服务

502 Bad Gateway 问题排查

  • 查看 PHP 日志,路径:/usr/local/php/var/log

  • 一般为“server reached pm.max_children setting (10), consider raising it”连接数问题,在“/usr/local/php/etc”下的所有配置文件中查找并修改相关设置即可(如改成 1000)。

计划任务(实例:定时备份数据库并通过 FTP 同步至其它服务器)

  • 创建可执行文件:vi dotask.sh

  • dotask.sh 的内容示例:

    DATE_TIME=`date +%Y_%m_%d_%H%M%S`;
    FILE_NAME=数据库名_backup_$DATE_TIME.sql;
    cd /home/mysqlbackup/;
    mysqldump -u数据库用户名 -p数据库密码 数据库名>$FILE_NAME;
    tar -zcf $FILE_NAME.tar.gz $FILE_NAME;
    rm $FILE_NAME;

    ftp -v -n FTP地址 << END
    user FTP用户名 FTP密码
    bin
    put 本地目录文件 目标路径文件
    bye
    END


    文件名乱码问题可以在行末加“;”来解决

  • 赋予执行权限:chmod 777 dotask.sh (ls 命令时呈绿色)

  • 编辑计划任务:crontab -e

  • crontab 书写规则:

    # 分 时 日 月 周 文件路径
    0 3 * * * /home/dotask.sh
    30 4 * * * /home/dotask2.sh


    更多帮助 

  • 重启 crond:/etc/init.d/crond restart

netstat

  • netstat -an | grep xxx.xxx.xxx.xxx 可查看此 IP 的 TCP 请求及端口

xoyozo 6 年前
6,121

本文不定时更新中……


具备 RESTful 相关知识会更有利于学习 ASP.NET Web API:RESTful API 学习笔记

ASP.NET Web API 官网:https://www.asp.net/web-api


服务 URI Pattern

ActionHttp verbURI说明
Get contact listGET/api/contacts列表
Get filtered contactsGET/api/contacts?$top=2筛选列表
Get contact by IDGET/api/contacts/id获取一项
Create new contactPOST/api/contacts增加一项
Update a contactPUT/api/contacts/id修改一项
Delete a contactDELETE/api/contacts/id
删除一项


返回类型Web API 创建响应的方式
void返回空 204 (无内容)
HttpResponseMessage转换为直接 HTTP 响应消息。
IHttpActionResult调用 ExecuteAsync 来创建 HttpResponseMessage,然后将转换为 HTTP 响应消息。
其他类型将序列化的返回值写入到响应正文中;返回 200 (正常)。

HttpResponseMessage

可提供大量控制的响应消息。 例如,以下控制器操作设置的缓存控制标头。

public class ValuesController : ApiController
{
    public HttpResponseMessage Get()
    {
        HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
        response.Content = new StringContent("hello", Encoding.Unicode);
        response.Headers.CacheControl = new CacheControlHeaderValue()
        {
            MaxAge = TimeSpan.FromMinutes(20)
        };
        return response;
    } 
}

IHttpActionResult

public IHttpActionResult Get (int id)
{
    Product product = _repository.Get (id);
    if (product == null)
    {
        return NotFound(); // Returns a NotFoundResult
    }
    return Ok(product);  // Returns an OkNegotiatedContentResult
}

其他的返回类型

响应状态代码为 200 (正常)。此方法的缺点是,不能直接返回错误代码,如 404。 但是,您可以触发 HttpResponseException 的错误代码


完善 Help 页

一般都是通过元数据注释(Metadata Annotations)来实现的描述的。


显示接口和属性的描述:

打开 HelpPage 区域的 App_Start 目录下的 HelpPageConfig.cs 文件,在 Register 方法的首行取消注释行:

config.SetDocumentationProvider(new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));

在项目右键属性“生成”页,勾选“XML 文档文件”,并填写与上述一致的路径(App_Data/XmlDocument.xml)。


给接口加上 ResponseType 显示响应描述和示例:[ResponseType(typeof(TEntity))]


在实体模型的属性上加入 RequiredAttribute 特性可提供请求或响应中的实体的属性描述,如:[Required]


推荐使用:Swashbuckle

关于格式


在 WebApiConfig.Register() 中加入以下代码以禁止以 XML 格式输出(请按需设置):

GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

Json 序列化去掉 k__BackingField

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver { IgnoreSerializableAttribute = true };

如果属性值为 null 则不序列化该属性

config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };



xoyozo 6 年前
4,275

制作类似下图中的拖拽排序功能:

image.png

1. 首先数据库该表中添加字段 sort,类型为 double(MySQL 中为 double(0, 0))。

2. 页面输出绑定数据(以 ASP.NET MVC 控制器为例):

public ActionResult EditSort()
{
    if (!zConsole.Logined) { return RedirectToAction("", "SignIn", new { redirect = Request.Url.OriginalString }); }

    db_auto2018Entities db = new db_auto2018Entities();

    return View(db.dt_dealer.Where(c => c.enabled).OrderBy(c => c.sort));
}

这里可以加条件列出,即示例中 enabled == true 的数据。

3. 前台页面引用 jQuery 和 jQuery UI。

4. 使用 <ul /> 列出数据:

<ul id="sortable" class="list-group gutter list-group-lg list-group-sp">
    @foreach (var d in Model)
    {
        <li class="list-group-item" draggable="true" data-id="@d.id">
            <span class="pull-left"><i class="fa fa-sort text-muted fa m-r-sm"></i> </span>
            <div class="clear">
                【id=@d.id】@d.name_full
            </div>
        </li>
    }
</ul>

5. 初始化 sortable,当拖拽结束时保存次序:

<script>
    var url_SaveSort = '@Url.Action("SaveSort")';
</script>
<script>
    $("#sortable").sortable({
        stop: function (event, ui) {
            // console.log('index: ' + $(ui.item).index())
            // console.log('id: ' + $(ui.item).data('id'))
            // console.log('prev_id: ' + $(ui.item).prev().data('id'))
            $.post(url_SaveSort, {
                id: $(ui.item).data('id'),
                prev_id: $(ui.item).prev().data('id')
            }, function (json) {
                if (json.result.success) {
                    // window.location.reload();
                } else {
                    toastr["error"](json.result.info);
                }
            }, 'json');
        }
    });
    $("#sortable").disableSelection();
</script>

这里回传到服务端的参数为:当前项的 id 值、拖拽后其前面一项的 prev_id 值(若移至首项则 prev_id 为 undefined)。

不使用 $(ui.item).index() 是因为,在有筛选条件的结果集中排序时,使用该索引值配合 LINQ 的 .Skip 会引起取值错误。

6. 控制器接收并保存至数据库:

[HttpPost]
public ActionResult SaveSort(int id, int? prev_id)
{
    if (!zConsole.Logined)
    {
        return Json(new { result = new { success = false, msg = "请登录后重试!" } }, JsonRequestBehavior.AllowGet);
    }

    db_auto2018Entities db = new db_auto2018Entities();

    dt_dealer d = db.dt_dealer.Find(id);

    // 拖拽后其前项 sort 值(若无则 null)(此处不需要加 enabled 等筛选条件)
    double? prev_sort = prev_id.HasValue
        ? db.dt_dealer.Where(c => c.id == prev_id).Select(c => c.sort).Single()
        : null as double?;

    // 拖拽后其后项 sort 值(若无前项则取首项作为后项)(必须强制转化为 double?,否则无后项时会返回 0,导致逻辑错误)
    double? next_sort = prev_id.HasValue
        ? db.dt_dealer.Where(c => c.sort > prev_sort && c.id != id).OrderBy(c => c.sort).Select(c => (double?)c.sort).FirstOrDefault()
        : db.dt_dealer.Where(c => c.id != id).OrderBy(c => c.sort).Select(c => (double?)c.sort).FirstOrDefault();

    if (prev_sort.HasValue && next_sort.HasValue)
    {
        d.sort = (prev_sort.Value + next_sort.Value) / 2;
    }
    if (prev_sort == null && next_sort.HasValue)
    {
        d.sort = next_sort.Value - 1;
    }
    if (prev_sort.HasValue && next_sort == null)
    {
        d.sort = prev_sort.Value + 1;
    }

    db.SaveChanges();

    return Json(new { item = new { id = d.id }, result = new { success = true } });
}

需要注意的是,当往数据库添加新项时,必须将 sort 值设置为已存在的最大 sort 值 +1 或最小 sort 值 -1。

var d = new dt_dealer
{
    name_full = "新建项",
    sort = (db.dt_dealer.Max(c => (double?)c.sort) ?? 0) + 1,
};


xoyozo 6 年前
6,424