博客 (72)

核心文件路径:/theme/html/demo*/src/js/components/core.datatable.js

所有参数的默认值见该文件 3369 行起。

data:

属性 功能
type 数据源类型 local / remote
source 数据源 链接或对象(见下方)
pageSize 每页项数 默认 10
saveState 刷新、重新打开、返回时仍保持状态 默认 true
serverPaging 是否在服务端实现分页 默认 false
serverFiltering 是否在服务端实现筛选 默认 false
serverSorting 是否在服务端实现排序 默认 false
autoColumns 为远程数据源启用自动列功能 默认 false
attr

data.source:

属性 功能
url 数据源地址
params 请求参数
query: {
}
headers 自定义请求的头
{
    'x-my-custom-header': 'some value',
    'x-test-header': 'the value'
}
map 数据地图,作用是对返回的数据进行整理和定位
function (raw) {
    console.log(raw)
    // sample data mapping
    var dataSet = raw;
    if (typeof raw.data !== 'undefined') {
        dataSet = raw.data;
    }
    return dataSet;
}

layout:

属性 功能
theme 主题 默认 default
class 包裹的 CSS 样式
scroll 在需要时显示横向或纵向滚动条 默认 false
height 表格高度 默认 null
minHeight 表格最小高度 默认 null
footer 是否显示表格底部 默认 false
header 是否显示表头 默认 true
customScrollbar 自定义的滚动条 默认 true
spinner Loading 样式
{
	overlayColor: '#000000',
	opacity: 0,
	type: 'loader',
	state: 'primary',
	message: true,
}
icons 表格中的 icon
{
	sort: {
	    asc: 'flaticon2-arrow-up', 
	    desc: 'flaticon2-arrow-down'
	},
	pagination: {
		next: 'flaticon2-next',
		prev: 'flaticon2-back',
		first: 'flaticon2-fast-back',
		last: 'flaticon2-fast-next',
		more: 'flaticon-more-1',
	},
	rowDetail: {
	    expand: 'fa fa-caret-down', 
	    collapse: 'fa fa-caret-right'
	},
}
sortable 是否支持按列排序 默认 true
resizable
是否支持鼠标拖动改变列宽 默认 false
filterable 在列中过滤 默认 false
pagination
显示分页信息 默认 true
editable
行内编辑 默认 false
columns
见本文下方
search
搜索
{
	// 按回车键确认
	onEnter: false,
	// 文本内容
	input: null,
	// 搜索延时
	delay: 400,
	// 键名
	key: null
}

layout.columns:

属性 功能 解释
field 字段名 对应 JSON 的属性名,点击表头时作为排序字段名
title 表头名 显示在表格头部
sortable 默认排序方式 可选:'asc' / 'desc'
width 单元格最小宽度 值与 CSS 值一致,填数字时默认单位 px
type 数据类型 'number' / 'date' 等,与本地排序有关
format 数据格式化 例格式化日期:'YYYY-MM-DD'
selector 是否显示选择框 布尔值或对象,如:{ class: '' }
textAlign 文字对齐方式 'center'
overflow 内容超过单元格宽度时是否显示 'visible':永远显示
autoHide 自适应显示/隐藏 布尔值
template 用于显示内容的 HTML 模板 function(row) { return row.Id; }
sortCallback 排序回调 自定义排序方式,参 local-sort.js

其它:

属性 功能 解释
translate 翻译

参 core.datatable.js 3512 行,简体中文示例:

translate: {
    records: {
        processing: '加载中...',
        noRecords: '没有找到相关内容',
    },
    toolbar: {
        pagination: {
            items: {
                default: {
                    first: '首页',
                    prev: '前一页',
                    next: '后一页',
                    last: '末页',
                    more: '更多',
                    input: '请输入跳转页码',
                    select: '设置每页显示项数',
                },
                info: '当前第 {{start}} - {{end}} 项 共 {{total}} 项',
            },
        },
    },
},


extensions

暂时没有找到对字符串内容进行自动 HTML 编码的属性,这可能带来 XSS 攻击风险,在 remote 方式中必须在服务端预先 HtmlEncode。即使在 layout.columns.template 中进行处理也是无济于事,恶意代码会在 ajax 加载完成后立即执行。


方法和事件:待完善。


更多信息请查询官方文档:https://keenthemes.com/keen/?page=docs&section=html-components-datatable

xoyozo 4 年前
4,723

如果富士施乐 DocuPrint P118 w 打印机开启后电脑无法连接,但路由器上显示已连网,很有可能是 IP 已变更(增添新设备后抢占了打印机原来的 IP 地址)。

这时候需要重新安装打印机驱动:(可能有不需要重装驱动的方法)

富士施乐 DocuPrint P118 w 在安装驱动时需要路由器支持 WPS/AOSS,

但小米路由器 Pro 中找不到该功能,而且实测无线方式安装打印机驱动失败。

我的方法是,找一台 TP-LINK 路由器,

将 SSID 和 WIFI 密码改成与小米路由器相同,

关闭小米路由器,

电脑连接这个 SSID,

然后按无线的方式安装打印机驱动程序,

完成后,关闭 TP-LINK 路由器,打开小米路由器,

网络启动后,重启打印机。

(打印时可能需要在窗口中选择另一个打印机名称)

xoyozo 4 年前
6,001

Nuget 安装:X.PagedList.Mvc.Core


控制器:

using X.PagedList;

public IActionResult Index(int page = 1)
{
    ……
    return View(q.ToPagedList(page, size));
}


视图:

@using X.PagedList
@using X.PagedList.Mvc.Core
@model IPagedList<xxx>

@Html.PagedListPager(Model, page => Url.Action("Index", new { page }))


自定义(options 默认值):

@Html.PagedListPager(
    Model, 
    page => Url.Action("Index", new { page }), 
    new X.PagedList.Mvc.Common.PagedListRenderOptionsBase
    {
        HtmlEncoder = HtmlEncoder.get_Default(),
        DisplayLinkToFirstPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToLastPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToPreviousPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToNextPage = PagedListDisplayMode.IfNeeded,
        DisplayLinkToIndividualPages = true,
        DisplayPageCountAndCurrentLocation = false, // 显示总页数和当前页码
        MaximumPageNumbersToDisplay = 10, // 最多显示页码数
        DisplayEllipsesWhenNotShowingAllPageNumbers = true,
        EllipsesFormat = "&#8230;",
        LinkToFirstPageFormat = "<<",
        LinkToPreviousPageFormat = "<",
        LinkToIndividualPageFormat = "{0}",
        LinkToNextPageFormat = ">",
        LinkToLastPageFormat = ">>",
        PageCountAndCurrentLocationFormat = "Page {0} of {1}.",
        ItemSliceAndTotalFormat = "Showing items {0} through {1} of {2}.",
        FunctionToDisplayEachPageNumber = null,
        ClassToApplyToFirstListItemInPager = null,
        ClassToApplyToLastListItemInPager = null,
        ContainerDivClasses = new string[1]
        {
            "pagination-container"
        },
        UlElementClasses = new string[1]
        {
            "pagination"
        },
        LiElementClasses = Enumerable.Empty<string>(),
        PageClasses = Enumerable.Empty<string>(),
        UlElementattributes = null,
        ActiveLiElementClass = "active",
        EllipsesElementClass = "PagedList-ellipses",
        PreviousElementClass = "PagedList-skipToPrevious",
        NextElementClass = "PagedList-skipToNext",
    })


保留地址栏参数:

@{ 
    string query = Context.Request.QueryString.Value;
}
@Html.PagedListPager(Model, page => Regex.IsMatch(query, @"[?&]page=\d+")
    ? Regex.Replace(query, @"([?&])page=\d+", $"$1page={page}")
    : (query.StartsWith("?") ? $"{query}&page={page}" : $"{query}?page={page}"),
    new X.PagedList.Web.Common.PagedListRenderOptionsBase
    {
        DisplayPageCountAndCurrentLocation = true,
        MaximumPageNumbersToDisplay = 5,
    })

这里从查询字符串中判断并替换 page 值,如果有更简单的方法敬请告知。比如 Webdiyer 的分页组件会自动携带所有参数。


更多使用方式参官方文档:https://github.com/dncuug/X.PagedList


附应用于 Unify Template(一款基于 Bootstrap 的 HTML 模板)中的配置:

<style>
    .u-pagination-v1-1--active .u-pagination-v1-1 { color: #fff; border-color: #72c02c; }
    .PagedList-pageCountAndLocation { float: right !important; }
</style>
@{
    string query = Context.Request.QueryString.Value;
}
@Html.PagedListPager(Model, page => Regex.IsMatch(query, @"[?&]page=\d+")
    ? Regex.Replace(query, @"([?&])page=\d+", $"$1page={page}")
    : (query.StartsWith("?") ? $"{query}&page={page}" : $"{query}?page={page}"),
    new X.PagedList.Web.Common.PagedListRenderOptionsBase
    {
        DisplayPageCountAndCurrentLocation = true,
        MaximumPageNumbersToDisplay = 5,
        UlElementClasses = new string[] { "list-inline" },
        LiElementClasses = new string[] { "list-inline-item" },
        PageClasses = new string[] { "u-pagination-v1__item", "u-pagination-v1-1", "g-pa-7-14" },
        ActiveLiElementClass = "u-pagination-v1-1--active",
        EllipsesElementClass = "g-pa-7-14",
    })


xoyozo 5 年前
9,765

* 本文凡使用变量 httpContextAccessor_httpContextAccessor 的地方都需要需要注入 Microsoft.AspNetCore.Http.IHttpContextAccessor

* 在视图(view)中应以 ViewContext 类引出


获取当前页面网址:

using Microsoft.AspNetCore.Http.Extensions;
string url = Request.GetDisplayUrl();


获取当前访问的域名和端口:

image.png


获取来源:

Request.GetTypedHeaders().Referer


判断 Scheme 是否为 https:

Request.IsHttps


获取客户端IP和端口、服务器IP和端口:

image.png


获取浏览器用户代理(UserAgent):

httpContextAccessor.HttpContext.Request.Headers[HeaderNames.UserAgent];


获取当前请求的唯一标识:

httpContextAccessor.HttpContext.TraceIdentifier

返回结果:80000564-0002-f700-b63f-84710c7967bb

用途:可作为生成随机数的种子。


获取客户端IP地址:

httpContextAccessor.HttpContext.Connection.RemoteIpAddress


获取当前项目根目录磁盘路径:

AppContext.BaseDirectory // 以“\”结尾

注意:此路径到项目根目录,而非网站根目录,网站根目录请自行追加,默认为 wwwroot\


编码/解码:(参数和返回值均为 string?

using System.Net;
WebUtility.HtmlEncode(myString)
WebUtility.HtmlDecode(myString)
WebUtility.UrlEncode(myString)
WebUtility.UrlDecode(myString)


更多:https://xoyozo.net/Blog/Index/Core


xoyozo 5 年前
3,871

确保磁盘未满,否则会提示各种无法连接。


  1. 在“小米WiFi”App 中开启对应路由器的“SAMBA 协议”(工具箱 - 更多工具 - SAMBA)。

  2. 在“小米WiFi”App 中开启相应电脑或设备的“全盘访问”。

  3. 通过 miwifi.com 下载安装 PC 客户端。

  4. 打开“此电脑”,“映射网络驱动器”或“添加一个网络位置”,填写路由器的地址和目录,如:“\\192.168.31.1\下载”。

  5. 如果上一步无法成功添加,那么首先需要检查 samba 服务器是否正常,可以在 iPhone 上安装“Remote File Manager”来验证。

  6. 如果 iPhone 连接正常,那么在电脑上打开“本地组策略编辑器”(命令行:gpedit.msc),在“计算机配置 - 管理模板 - 网络 - Lanman 工作站”右侧,双击“启用不安全的来宾登录”,改为“已启用”。Win7 用户参考此文


注意:电脑必须运行 PC 客户端才能访问小米路由器硬盘。

xoyozo 5 年前
14,638
  1. 微信的 H5 页面前端引导到:

    https://api.magcloud.cc/magshare/{siteId}?jump_url={jump_url}&content_url={content_url}

    各参数含义见官方文档:http://doc.magcloud.net/325339

    content_url 地址(一般仍为活动页面)接收参数 magshareredirect,值为 1 则跳转到自定义的引导页。

  2. 自定义引导页按 iOS 和安卓显示图文和箭头,引导用户点击右上角菜单,在浏览器中打开。

  3. 在浏览器 H5 中引导打开:

    {siteId}://pagejump?jump_url={jump_url}

    各参数含义见第 1 步中的文档。

    这里涉及一个“若未安装则引导安装”的过程,可以选择下方合适的一种方式实现:

    • A 标签的 href 填入下载地址,onclick 事件 location 到 App

    • onclick 事件 location 到 App,再用 setTimeOut location 到下载地址

    • 若仍无法实现预期效果,可以在弹出层中放置“未安装,前往下载”和“已安装,立即打开”两个按钮,让用户自己选择

  4. 若下载地址为应用宝,那么在 iOS 中可能会出现“打开 App 后继而自动打开 App Store”的情况,可以自建中转的 App 介绍页引导到 App Store 或应用宝。

  5. 分别实现微信和 MAGAPP 客户端的分享

xoyozo 5 年前
5,041

完整操作步骤如下:

  1. 安装 NuGet 包:Microsoft.AspNet.Web.Optimization

  2. 打开 Views 目录(如果是应用于区域,则为区域的 Views 目录)中的 web.config,在 <namespaces /> 节点中添加

    <add namespace="System.Web.Optimization" />
  3. App_Start 目录中创建类文件 BundleConfig.cs,更改其命名空间为应用程序的默认命名空间(即移除 .App_Start),创建方法:

    public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new StyleBundle("~/虚拟路径(不能有点)").Include("~/CSS文件路径"));
        bundles.Add(new ScriptBundle("~/虚拟路径(不能有点)").Include("~/JS文件路径"));
    }

    虚拟路径应避免与页面访问路径相同。Include 可包含多个文件,效果是合并输出,注意引用的顺序。

  4. 打开 Global.asax,在 Application_Start() 事件中添加代码

    BundleTable.EnableOptimizations = true; // 该设置使在开发模式中实现压缩代码,不设置则仅在发布后压缩代码
    BundleConfig.RegisterBundles(BundleTable.Bundles);
  5. 视图页面中引用样式表或脚本

    @Styles.Render("~/CSS虚拟路径")
    @Scripts.Render("~/JS虚拟路径")

    使用 Render 的好处是,ASP.NET 会自动给引用地址加上参数,可在更改脚本或样式表内容后更改这些参数使浏览器缓存立即失效。

如果你的项目中已经安装并使用 Bundle,那么只需要参考第 4 步,将 BundleTableEnableOptimixations 设为 true

以下是一些常见异常的解决方法:


The name 'Styles' does not exist in the current context

The name 'Scripts' does not exist in the current context

解决:参步骤 2。


引用的样式表或脚本不存在(报 404 错误)

解决:步骤 3 中的虚拟路径不规范。

xoyozo 5 年前
5,292

原标题:关于 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 6 年前
6,705

当微信支付的 notify_url 填写的是 https 的回调地址时,如果遇到支付成功但没有接收到回调的情况,可能是服务器开启了 SNI。

SNI,即服务器名称指示,用于在一台服务器上支持多个网站使用不同的 SSL 证书。

解决方案:

  • 方法一、notify_url 改为 http 的回调地址,缺点是容易被运营商 QJ,而且如果日后网站开启强制要求 https 访问就会使回调失败;

  • 方法二、【不推荐】可以为该网站单独配置一台服务,不使用 SNI,缺点是增加成本;

  • 方法三、【推荐】该网站仍然“需要服务器名称指示”,在 IIS 中给默认网站(不是当前网站)添加一个 https 的域名绑定,不勾选“需要服务器名称指示”,证书随便选一个。缺点是时间一长容易忘记有这回事,不要轻易删除该绑定就好了,而且在网站搬迁的时候也同样要做该配置。

image.png

感谢 V2EX

xoyozo 6 年前
7,658

场景:每天带笔记本电脑上班,公司使用固定 IP 上网,家里网络的网段又跟公司不一样。


方法 1:两个网络环境分别使用有线连接和无线连接(鉴于笔记本无线网卡不支持 5G(802.11ac),或者有其它需求必须都使用有线连接的不适用此方法)。

方法 2:修改家里路由器的局域网 IP 地址,使其网段与公司相同(虽然仅需要一次修改,但部分路由器不允许修改局域网 IP 地址);

方法 3:使用第三方软件一键切换(有安全隐患,且可能导致电脑网络设置出现错误);

方法 4(推荐):设置电脑网络连接同时使用两个 IP,具体方法如下:


打开“以太网 属性”,双击“Internet 协议版本 4 (TCP/IPv4)”,配置其中一个网络环境的 IP 地址和网关(例如我在公司上网的 IP 是 192.168.1.5,网关是 192.168.1.1)

image.png

点击“高级”,在 IP 地址栏添加另一个网络的 IP(如 192.168.31.5),在“默认网关”处添加这个网络的网关(如 192.168.31.1)

image.png

这样设置后,不管到公司还是回到家,只要网线一插就能上网,不需要每天更换 IP 地址设置了。

image.png

(图中显示了两个网络名称)

xoyozo 6 年前
6,875