[root ~]# yum update xxx
Loaded plugins: security
Setting up Update Process
http://mirrors.aliyun.com/centos/6/os/x86_64/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"
Trying other mirror.
To address this issue please refer to the below wiki article
https://wiki.centos.org/yum-errors
If above article doesn't help to resolve this issue please use https://bugs.centos.org/.
http://mirrors.aliyuncs.com/centos/6/os/x86_64/repodata/repomd.xml: [Errno 12] Timeout on http://mirrors.aliyuncs.com/centos/6/os/x86_64/repodata/repomd.xml: (28, 'connect() timed out!')
Trying other mirror.
http://mirrors.cloud.aliyuncs.com/centos/6/os/x86_64/repodata/repomd.xml: [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 404 Not Found"
Trying other mirror.
Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again
售后工程师:
您好,CentOS 6 已经停止技术支持通知 新购实例或者旧有的Centos 6 操作系统会导致yum安装失败,相关公告请见下面内容;
这边建议您考虑将数据备份一下,升级至Centos 7 版本。如果一定要使用,需要手动切换源,您可以将由原的yum 源做下备份,对/etc/yum.repos.d 内容进行清空处理,然后参考下面的教程做下源的更换处理。
有其他咨询,您继续反馈
简言之,对照自己的版本号,将文件 /etc/yum.repos.d/CentOS-Base.repo 与 /etc/yum.repos.d/epel.repo 的内容替换成教程中的内容即可。

.menu-nav 包裹
<ul class="menu-nav">
...
</ul>
.menu-section 区段
<li class="menu-section">
<h4 class="menu-text">区段</h4>
<i class="menu-icon ki ki-bold-more-hor icon-md"></i>
</li>
.menu-item 菜单
<li class="menu-item" aria-haspopup="true">
<a href="###" class="menu-link">
<span class="svg-icon menu-icon">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<rect x="0" y="0" width="24" height="24" />
<path d="M3,16 L5,16 C5.55228475,16 6,15.5522847 6,15 C6,14.4477153 5.55228475,14 5,14 L3,14 L3,12 L5,12 C5.55228475,12 6,11.5522847 6,11 C6,10.4477153 5.55228475,10 5,10 L3,10 L3,8 L5,8 C5.55228475,8 6,7.55228475 6,7 C6,6.44771525 5.55228475,6 5,6 L3,6 L3,4 C3,3.44771525 3.44771525,3 4,3 L10,3 C10.5522847,3 11,3.44771525 11,4 L11,19 C11,19.5522847 10.5522847,20 10,20 L4,20 C3.44771525,20 3,19.5522847 3,19 L3,16 Z" fill="#000000" opacity="0.3" />
<path d="M16,3 L19,3 C20.1045695,3 21,3.8954305 21,5 L21,15.2485298 C21,15.7329761 20.8241635,16.200956 20.5051534,16.565539 L17.8762883,19.5699562 C17.6944473,19.7777745 17.378566,19.7988332 17.1707477,19.6169922 C17.1540423,19.602375 17.1383289,19.5866616 17.1237117,19.5699562 L14.4948466,16.565539 C14.1758365,16.200956 14,15.7329761 14,15.2485298 L14,5 C14,3.8954305 14.8954305,3 16,3 Z" fill="#000000" />
</g>
</svg>
</span>
<span class="menu-text">一级菜单(无子菜单)</span>
</a>
</li>
其中,<svg /> 可以替换成其它图标库,如:
<li class="menu-item" aria-haspopup="true">
<a href="###" class="menu-link">
<span class="svg-icon menu-icon">
<i class="fab fa-app-store-ios"></i>
</span>
<span class="menu-text">一级菜单(无子菜单)</span>
</a>
</li>
并修正样式:
.aside-menu .menu-nav > .menu-item > .menu-heading .menu-icon i,
.aside-menu .menu-nav > .menu-item > .menu-link .menu-icon i { height: 23px; width: 23px; line-height: 23px; text-align: center; vertical-align: middle; font-size: 1.25rem; }
.menu-item-submenu 表示该 .menu-item 有子菜单,即内部包含 .menu-submenu。该规则在任意一级菜单均有效。
.menu-item-open 表示该 .menu-item 当前是打开状态(高亮),否则为闭合状态,需配合 <i class="menu-arrow"></i> 使用。该规则在任意一级菜单均有效。
.menu-item-active 表示该 .menu-item 对应当前页面,效果为灰色背景且文字持续高亮。
.menu-item-parent 作为一级菜单在不同设备上展示的替代,位于一级菜单下的 .menu-submenu 下的 .menu-subnav 内部。
.menu-link 表示可点击(hover 效果),用于 .menu-item 下的 <a /> 或 .menu-item-parent 下的 <span />。
aria-haspopup="true" 每个 .menu-item 都有。
data-menu-toggle="hover" 每个 .menu-item-submenu 都有。
.menu-icon 一级菜单项的左侧图标,支持 <svg /> 或 <i />。
.menu-bullet 非一级菜单项的左侧图标,与 .menu-text 同级,可选 .menu-bullet-line / .menu-bullet-dot。
.menu-text 菜单文字。
.menu-label 菜单项右侧徽章,与 .menu-text 同级。
.menu-arrow 菜单项右侧箭头(当包含子菜单时使用),与 .menu-text 同级。
.menu-toggle 放在 .menu-item-submenu 内部的 .menu-link,与 .menu-item-submenu 上的 data-menu-toggle="hover" 同时出现。
完整示例:
<ul class="menu-nav">
<li class="menu-item" aria-haspopup="true">
<a href="index.html" class="menu-link">
<span class="svg-icon menu-icon">
<!--begin::Svg Icon | path:assets/media/svg/icons/Design/Layers.svg-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon points="0 0 24 0 24 24 0 24" />
<path d="M12.9336061,16.072447 L19.36,10.9564761 L19.5181585,10.8312381 C20.1676248,10.3169571 20.2772143,9.3735535 19.7629333,8.72408713 C19.6917232,8.63415859 19.6104327,8.55269514 19.5206557,8.48129411 L12.9336854,3.24257445 C12.3871201,2.80788259 11.6128799,2.80788259 11.0663146,3.24257445 L4.47482784,8.48488609 C3.82645598,9.00054628 3.71887192,9.94418071 4.23453211,10.5925526 C4.30500305,10.6811601 4.38527899,10.7615046 4.47382636,10.8320511 L4.63,10.9564761 L11.0659024,16.0730648 C11.6126744,16.5077525 12.3871218,16.5074963 12.9336061,16.072447 Z" fill="#000000" fill-rule="nonzero" />
<path d="M11.0563554,18.6706981 L5.33593024,14.122919 C4.94553994,13.8125559 4.37746707,13.8774308 4.06710397,14.2678211 C4.06471678,14.2708238 4.06234874,14.2738418 4.06,14.2768747 L4.06,14.2768747 C3.75257288,14.6738539 3.82516916,15.244888 4.22214834,15.5523151 C4.22358765,15.5534297 4.2250303,15.55454 4.22647627,15.555646 L11.0872776,20.8031356 C11.6250734,21.2144692 12.371757,21.2145375 12.909628,20.8033023 L19.7677785,15.559828 C20.1693192,15.2528257 20.2459576,14.6784381 19.9389553,14.2768974 C19.9376429,14.2751809 19.9363245,14.2734691 19.935,14.2717619 L19.935,14.2717619 C19.6266937,13.8743807 19.0546209,13.8021712 18.6572397,14.1104775 C18.654352,14.112718 18.6514778,14.1149757 18.6486172,14.1172508 L12.9235044,18.6705218 C12.377022,19.1051477 11.6029199,19.1052208 11.0563554,18.6706981 Z" fill="#000000" opacity="0.3" />
</g>
</svg>
<!--end::Svg Icon-->
</span>
<span class="menu-text">Dashboard</span>
</a>
</li>
<li class="menu-section">
<h4 class="menu-text">区段 A(一级菜单示例)</h4>
<i class="menu-icon ki ki-bold-more-hor icon-md"></i>
</li>
<li class="menu-item" aria-haspopup="true">
<a href="item1" class="menu-link">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-one"></i>
</span>
<span class="menu-text">菜单 A</span>
</a>
</li>
<li class="menu-item" aria-haspopup="true">
<a href="item2" class="menu-link">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-two"></i>
</span>
<span class="menu-text">菜单 B(带徽章)</span>
<span class="menu-label">
<span class="label label-rounded label-primary">6</span>
</span>
</a>
</li>
<li class="menu-item menu-item-active" aria-haspopup="true">
<a href="item2" class="menu-link">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-three"></i>
</span>
<span class="menu-text">菜单 C(高亮)</span>
</a>
</li>
<li class="menu-section">
<h4 class="menu-text">区段 B(二级菜单示例)</h4>
<i class="menu-icon ki ki-bold-more-hor icon-md"></i>
</li>
<li class="menu-item menu-item-submenu" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-one"></i>
</span>
<span class="menu-text">一级菜单(默认关闭)</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item menu-item-parent" aria-haspopup="true">
<span class="menu-link">
<span class="menu-text">一级菜单(默认关闭)</span>
</span>
</li>
<li class="menu-item" aria-haspopup="true">
<a href="custom/apps/inbox.html" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单 a</span>
</a>
</li>
<li class="menu-item" aria-haspopup="true">
<a href="custom/apps/inbox.html" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单 b(带徽章)</span>
<span class="menu-label">
<span class="label label-danger label-inline">new</span>
</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item menu-item-submenu menu-item-here menu-item-open" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-two"></i>
</span>
<span class="menu-text">一级菜单(高亮/默认打开)</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item menu-item-parent" aria-haspopup="true">
<span class="menu-link">
<span class="menu-text">一级菜单(高亮/默认打开)</span>
</span>
</li>
<li class="menu-item menu-item-active" aria-haspopup="true">
<a href="custom/apps/inbox.html" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单 c(高亮)</span>
</a>
</li>
<li class="menu-item" aria-haspopup="true">
<a href="custom/apps/inbox.html" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单 d(带徽章)</span>
<span class="menu-label">
<span class="label label-danger label-inline">new</span>
</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-section">
<h4 class="menu-text">区段 C(三级菜单示例)</h4>
<i class="menu-icon ki ki-bold-more-hor icon-md"></i>
</li>
<li class="menu-item menu-item-submenu menu-item-open menu-item-here" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<span class="svg-icon menu-icon">
<i class="fas fa-dice-one"></i>
</span>
<span class="menu-text">一级菜单</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item menu-item-parent" aria-haspopup="true">
<span class="menu-link">
<span class="menu-text">一级菜单</span>
</span>
</li>
<li class="menu-item menu-item-submenu menu-item-open menu-item-here" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单(默认打开)</span>
<span class="menu-label">
<span class="label label-rounded label-primary">6</span>
</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item" aria-haspopup="true">
<a href="custom/apps/user/list-default.html" class="menu-link">
<i class="menu-bullet menu-bullet-dot"><span></span></i>
<span class="menu-text">三级菜单 1</span>
</a>
</li>
<li class="menu-item menu-item-active" aria-haspopup="true">
<a href="custom/apps/user/list-datatable.html" class="menu-link">
<i class="menu-bullet menu-bullet-dot"><span></span></i>
<span class="menu-text">三级菜单 2(高亮)</span>
</a>
</li>
</ul>
</div>
</li>
<li class="menu-item menu-item-submenu" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">二级菜单(默认关闭)</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item menu-item-submenu" aria-haspopup="true" data-menu-toggle="hover">
<a href="javascript:;" class="menu-link menu-toggle">
<i class="menu-bullet menu-bullet-dot"><span></span></i>
<span class="menu-text">二级菜单(默认关闭)</span>
<i class="menu-arrow"></i>
</a>
<div class="menu-submenu">
<i class="menu-arrow"></i>
<ul class="menu-subnav">
<li class="menu-item" aria-haspopup="true">
<a href="custom/apps/profile/profile-1/overview.html" class="menu-link">
<i class="menu-bullet menu-bullet-line"><span></span></i>
<span class="menu-text">三级菜单 3</span>
</a>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
效果:
关于手风琴功能:Metronic 菜单已实现手风琴功能,即当展开一个闭合的菜单时,非当前页面所在菜单项的房系菜单会自动闭合。

报错:
HTTP Error 500.30 - ASP.NET Core app failed to start
Common solutions to this issue:
The app failed to start
The app started but then stopped
The app started but threw an exception during startup
Troubleshooting steps:
Check the system event log for error messages
Enable logging the application process' stdout messages
Attach a debugger to the application process and inspect
For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028265
解决:
直接运行网站根目录的 .exe 启动文件可以找到答案。
一个常见的原因是:因 nuget 包升级(特别是需要服务器端安装组件的包)导致的发布后仍然是低版本的包,删除项目中的 /obj/ 目录重新发布即可。

核心文件路径:/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 | 请求参数 |
|
headers |
自定义请求的头 |
|
map | 数据地图,作用是对返回的数据进行整理和定位 |
|
layout:
属性 | 功能 | 值 |
theme | 主题 | 默认 default |
class | 包裹的 CSS 样式 | |
scroll | 在需要时显示横向或纵向滚动条 | 默认 false |
height | 表格高度 | 默认 null |
minHeight | 表格最小高度 | 默认 null |
footer | 是否显示表格底部 | 默认 false |
header | 是否显示表头 | 默认 true |
customScrollbar | 自定义的滚动条 | 默认 true |
spinner |
Loading 样式 |
|
icons | 表格中的 icon |
|
sortable | 是否支持按列排序 | 默认 true |
resizable |
是否支持鼠标拖动改变列宽 | 默认 false |
filterable | 在列中过滤 | 默认 false |
pagination |
显示分页信息 | 默认 true |
editable |
行内编辑 | 默认 false |
columns |
列 | 见本文下方 |
search |
搜索 |
|
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 行,简体中文示例:
|
extensions |
暂时没有找到对字符串内容进行自动 HTML 编码的属性,这可能带来 XSS 攻击风险,在 remote 方式中必须在服务端预先 HtmlEncode。即使在 layout.columns.template 中进行处理也是无济于事,恶意代码会在 ajax 加载完成后立即执行。
方法和事件:待完善。
更多信息请查询官方文档:https://keenthemes.com/keen/?page=docs§ion=html-components-datatable

protected void Page_Load(object sender, EventArgs e)
{
int a = 1;
Task.Run(() =>
{
a = PlusOne(1);
}).Wait(3000);
b = a;
}
private static int PlusOne(int n)
{
System.Threading.Thread.Sleep(4000);
return n + 1;
}
上例中使用 Task.Run 创建一个新线程调用 PlusOne 方法,并设置超时时间为 3000 毫秒。若方法 PlusOne 在 3 秒内完成,则变量 a 加 1 成功,否则 a 仍为原值。
注意:Wait 方法作用是在指定时间内等待 Task.Run 执行完毕,并不会在超时后终止该线程。

本文适用于 Window,CentOS(Linux) 系统请移步:http://xoyozo.net/Blog/Details/inotify-tools
FileSystemWatcher
关于监视文件系统事件的介绍
https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2008/ch2s8yd7(v=vs.90)
以控制台应用程序为例:
using System;
using System.IO;
using System.Security.Permissions;
public class Watcher
{
public static void Main()
{
Run();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private static void Run()
{
string[] args = Environment.GetCommandLineArgs();
// If a directory is not specified, exit program.
if (args.Length != 2)
{
// Display the proper way to call the program.
Console.WriteLine("Usage: Watcher.exe (directory)");
return;
}
// Create a new FileSystemWatcher and set its properties.
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = args[1];
// Watch for changes in LastAccess and LastWrite times, and
// the renaming of files or directories.
watcher.NotifyFilter = NotifyFilters.LastAccess
| NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;
// Only watch text files.
watcher.Filter = "*.txt";
// Add event handlers.
watcher.Changed += OnChanged;
watcher.Created += OnChanged;
watcher.Deleted += OnChanged;
watcher.Renamed += OnRenamed;
// Begin watching.
watcher.EnableRaisingEvents = true;
// Wait for the user to quit the program.
Console.WriteLine("Press 'q' to quit the sample.");
while (Console.Read() != 'q') ;
}
}
// Define the event handlers.
private static void OnChanged(object source, FileSystemEventArgs e) =>
// Specify what is done when a file is changed, created, or deleted.
Console.WriteLine($"File: {e.FullPath} {e.ChangeType}");
private static void OnRenamed(object source, RenamedEventArgs e) =>
// Specify what is done when a file is renamed.
Console.WriteLine($"File: {e.OldFullPath} renamed to {e.FullPath}");
}

本文适用于 CentOS(Linux),Window 系统请移步:https://xoyozo.net/Blog/Details/FileSystemWatcher
安装
参照官方说明:https://github.com/inotify-tools/inotify-tools/wiki
以 CentOS 为例:
安装 EPEL :
yum install -y epel-release && yum update
安装 inotify-tools:
yum install inotify-tools
在 CentOS-7 中
yum --enablerepo=epel install inotify-tools
v3.14-8.el7.×86_64 as of 4-18-2018
配置
创建 Shell 脚本文件:
#!/bin/bash
inotifywait -mrq -e modify,attrib,move,create,delete /要监视的目录 | while read dir event file;
do
curl -d "df=${dir}${file}&ev=${event}" https://xxx.xxx.xxx/api/inotify/
done
并将该文件设置为可执行:chmod +x xxx.sh
注:上述示例将对文件的部分操作事件信息传递到远程接口。inotifywait 与 curl 的用法请自行百度。
如果需要忽略部分文件路径,可以使用正则表达式进行过滤,例:
#!/bin/bash
inotifywait -mrq -e modify,attrib,move,create,delete /要监视的目录 | while read dir event file;
do
df=${dir}${file};
if [[ ! $df =~ ^/www/wwwroot/[0-9a-z]+.xxx.com/[0-9a-zA-Z]+/Runtime/Cache/[0-9a-zA-Z]+/[0-9a-f]{32}.php$
&& ! $df =~ ^/www/wwwroot/[0-9a-z]+.xxx.com/[0-9a-zA-Z]+/Runtime/Logs/[0-9a-zA-Z]+/[0-9]{2}_[0-9]{2}_[0-9]{2}.log$
]]; then
curl -d "df=${df}&ev=${event}" https://xxx.xxx.xxx/api/inotify/
else
echo "Ignored: $df"
fi
done
注意:bash 中使用 [[ string =~ regex ]] 表达式进行正则匹配,“!”取反,“&&”为且,书写时不要吝啬使用空格,否则程序可能不会按预期运行。
执行
先直接执行 sh 命令,排查一些错误。
Failed to watch /www/wwwroot; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches'.
因被监视的目录中文件数超过默认值 8192 提示失败,更改该值即可。
echo 8192000 > /proc/sys/fs/inotify/max_user_watches
设置开机自动运行,参:https://xoyozo.net/Blog/Details/linux-init-d。

这个现象在国产浏览器上使用极速内核时出现,原因是百度编辑器上传图片功能通过 <form /> 提交到 <iframe /> 时,因跨域导致 cookie 丢失。
ASP.NET 的 ASP.NET_SessionId
默认的 SameSite
属性值为 Lax
,将其设置为 None
即可:
protected void Session_Start(object sender, EventArgs e)
{
// 解决在部分国产浏览器上使用百度编辑器上传图片时(iframe),未通过 cookie 传递 ASP.NET_SessionId 的问题
string ua = Request.UserAgent ?? "";
var browsers = new string[] { "QQBrowser/" /*, "Chrome/" 不要直接设置 Chrome,真正的 Chrome 会出现正常页面不传递 Cookie 的情况 */ };
bool inWeixin = ua.Contains("MicroMessenger/"); // 是否在微信中打开(因微信PC端使用QQ浏览器内核,下面的设置会导致其网页授权失败)
if (browsers.Any(c => ua.Contains(c)) && !inWeixin)
{
Response.Cookies["ASP.NET_SessionId"].SameSite = SameSiteMode.None;
}
}
以上代码加入到 Global.asax
的 Session_Start
方法中,或百度编辑器所在页面。
注意一:SameSite=None 时会将父页面的 cookie 带入到 iframe 子页的请求中,从而导致 cookie 泄露,请确保项目中无任何站外引用,如网站浏量统计器、JS组件远程CDN等!
注意二:微信PC版的内嵌浏览器使用QQ浏览器内核,以上代码会导致其微信网页授权不能正常执行。

使用 JS 根据屏幕宽度来计算页面尺寸和字体大小并不是一个好办法。
rem 单位是跟随网页根元素的 font-size 改变而自动改变的,是一个相对的长度单位,非常适合在不同手机界面上自适应屏幕大小。
一般的手机浏览器的默认字体大小为 16px。即:
:root { font-size: 16px; } /* 在 HTML 网页中,:root 选择器相当于 html */
也就是说,如果我定义一个宽度为 1rem,那么它的实际宽度为 16px。反过来说,如果设计稿宽度为 1000px,那么相当于 1000÷16=62.5rem。因此,我们设置一个 62.5rem 的宽度,即可正常显示 1000px 的设计效果。
为了适应不同屏幕尺寸的手机,只需按比例换算更改 :root 的 font-size 即可。这个比例是由“窗口宽度 ÷ 设计稿宽度”得到的,姑且称它为“窗设比”。
以 iPhone X 逻辑宽度 375px 为例,设计稿宽度 1000px 时,窗设比为:0.375。:root 的 font-size 将会被重置为 16 * 0.375 = 6px。上面的 62.5rem 宽度将对应 iPhone X 宽度为 62.5 * 6 = 375px,正好是屏幕逻辑宽度。
根据这个思路,理论上,我们只需要使用 CSS 将 :root 的 font-size 设置为 1px,然后使用 JS 重置为与“窗设比”相乘的积(本例中将被重置为 0.375px)。这样,我们可以不通过换算,只需要更改单位,将设计稿中的 500px 直接写入到 CSS 为 500rem,即可实现在 iPhone X 上显示逻辑宽度为(500 * 0.375 =)187.5px,即设计稿中的 1/2 宽度对应到屏幕上 1/2 的宽度。
实际上,部分安卓手机(如华为某旗舰机)不支持 :root 的 font-size 小于 12px,其它一些浏览器也会出现小于 12px 的文字以 12px 显示。
为了避免在任何环节出现小于 12px 的 font-size 值,且不增加设计稿尺寸到 CSS 数值的换算难度,我们设计了以下思路:
约定“设样比(设计稿的 px 值与 CSS 的 rem 值的比)”为 100;
使用 JS 将 :root 的 font-size 重置为“设样比”与“窗设比(窗口宽度 ÷ 设计稿宽度)”的乘积;
计算 CSS 时的 rem 值只需从设计稿中获取 px 值再除以“设样比”100 即可。
这样做的另一个好处是,不用要求设计师必须按多少尺寸来设计,当然按主流尺寸来建议是可行的。
完整代码(jQuery 版):
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<title>Index</title>
<style>
body { margin: 0; text-align: center; }
#app { margin: 0 auto; background-color: #EEE; display: none; }
/* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
.whole { background-color: #D84C40; width: 10rem; }
.half { background-color: #3296FA; width: 5rem; }
.half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
</style>
</head>
<body>
<div id="app">
<div class="whole">100%</div>
<div class="half">50%</div>
<div class="half2">50%</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
// [函数] 重置尺寸
function fn_resize() {
// 设计稿宽度(px)
var designsWidth = 1000;
// 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
var px2rem = 100;
// 限制 #app 的最大宽度为设计稿宽度
$('#app').css('max-width', designsWidth).css('min-height', $(window).height());
// 重置 :root 的 font-size
var appWidth = Math.min($(window).width(), designsWidth);
$(':root').css('font-size', px2rem * appWidth / designsWidth);
$('#app').show();
}
// 页面加载完成后重置尺寸
$(fn_resize);
// 改变窗口大小时重置尺寸
$(window).resize(fn_resize);
</script>
</body>
</html>
完整代码(Vue2 版):
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<title>Index</title>
<style>
body { margin: 0; text-align: center; }
#app { margin: 0 auto; background-color: #EEE; }
/* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
.whole { background-color: #D84C40; width: 10rem; }
.half { background-color: #3296FA; width: 5rem; }
.half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
</style>
</head>
<body>
<div id="app" v-bind:style="{ maxWidth: designsWidth + 'px', minHeight: appMinHeight + 'px' }" style="display: none;" v-show="appShow">
<div class="whole">100%</div>
<div class="half">50%</div>
<div class="half2">50%</div>
<div>appWidth: {{ appWidth }}</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
var app = new Vue({
el: '#app',
data: {
// 设计稿宽度(px)
designsWidth: 1000,
// 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
px2rem: 100,
// #app 的 width
appWidth: 0, // 勿改
appMinHeight: 0, // 勿改
appShow: false, // 勿改
},
mounted: function () {
// 页面加载完成后重置尺寸
this.fn_resize();
const that = this;
// 改变窗口大小时重置尺寸
window.onresize = () => {
return (() => {
console.log('RUN window.onresize()');
that.fn_resize();
})();
};
},
watch: {
// 侦听 appWidth 更改 root 的 font-size
appWidth: function () {
console.log('RUN watch: appWidth');
var root = document.getElementsByTagName("html")[0];
root.style.fontSize = (this.px2rem * this.appWidth / this.designsWidth) + 'px';
this.appShow = true;
}
},
methods: {
fn_resize: function () {
console.log('RUN methods: fn_resize()');
this.appWidth = Math.min(document.body.clientWidth, this.designsWidth);
this.appMinHeight = document.documentElement.clientHeight;
}
}
});
</script>
</body>
</html>
完整代码(Vue3 版):
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<title>Index</title>
<style>
body { margin: 0; text-align: center; }
#app > div { display: none; margin: 0 auto; background-color: #EEE; }
/* 长度计算方法:从设计稿获得长度(例如 160px),除以 px2rem 值(本例为 100),得到 1.6rem */
.whole { background-color: #D84C40; width: 10rem; }
.half { background-color: #3296FA; width: 5rem; }
.half2 { background-color: #3296FA; width: 5rem; margin-left: 5rem; }
</style>
</head>
<body>
<div id="app">
<div style="display: none;" v-bind:style="{ maxWidth: designsWidth + 'px', minHeight: appMinHeight + 'px', display: appShow ? 'block' : 'none' }">
<div class="whole">100%</div>
<div class="half">50%</div>
<div class="half2">50%</div>
<div>appWidth: {{ appWidth }}</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<script>
const app = Vue.createApp({
data: function () {
return {
// 设计稿宽度(px)
designsWidth: 1000,
// 约定的“设计稿 px 值与 CSS rem 值的比”,为方便计算,一般无需改动
px2rem: 100,
// #app 的 width
appWidth: 0, // 勿改
appMinHeight: 0, // 勿改
appShow: false, // 勿改
}
},
mounted: function () {
// 页面加载完成后重置尺寸
this.fn_resize();
const that = this;
// 改变窗口大小时重置尺寸
window.onresize = () => {
return (() => {
console.log('RUN window.onresize()');
that.fn_resize();
})();
};
},
watch: {
// 侦听 appWidth 更改 root 的 font-size
appWidth: function () {
console.log('RUN watch: appWidth');
var root = document.getElementsByTagName("html")[0];
root.style.fontSize = (this.px2rem * this.appWidth / this.designsWidth) + 'px';
this.appShow = true;
}
},
methods: {
fn_resize: function () {
console.log('RUN methods: fn_resize()');
this.appWidth = Math.min(document.body.clientWidth, this.designsWidth);
this.appMinHeight = document.documentElement.clientHeight;
}
}
});
const vm = app.mount('#app');
</script>
</body>
</html>
示例中 CSS 初始 :root 的 font-size 为 16px(一个较小值,防止页面加载时瞬间出现大号文字影响用户体验),经过 fn_resize 后,:root 的 font-size 被设置为(100 * 375 / 1000 =)37.5px(iPhone X 中),那么宽度为 1000px 的设计稿中的 500px 换算到 CSS 中为 5rem,也即 37.5 * 5 = 187.5px,就是 iPhone X 的屏幕宽度的一半。
示例中 id 为 app 的 div 是用来在 PC 浏览器中限制页面内容最大宽度的(类似微信公众号发布的文章),如果网页不需要在 PC 端显示,jQuery 版代码中的 $('#app').width() 可以用 $(window).width() 来代替。
这个 div#app 一般设计有背景色,用于在宽度超过设计稿的设备上显示时区别于 body 的背景。但是当网页内容不超过一屏时,div#app 高度小于窗口,示例中与 appMinHeight 相关的代码就是为了解决这个问题。
示例中 div#app 隐藏/显示相关代码用于解决在页面加载初期由于 font-size 值变化引起的一闪而过的排版错乱。
最后补充一点,如果改变窗口大小时涉及执行耗时的操作,为避免页面卡顿,可以参考这篇文章添加函数防抖:https://xoyozo.net/Blog/Details/js-function-anti-shake

ueditor.all.min.js: Uncaught DOMException: Blocked a frame with origin "http://localhost:4492" from accessing a cross-origin frame.
at baidu.editor.ui.Dialog.close
当引用第三方 CDN 静态资源的方式部署百度编辑器时,使用多图上传、涂鸦等功能(弹出框使用 iframe 标签引用 CDN 上的网页)会报上述跨域错误。
官方并没有给出这种部署方案(即客户端页面与页面之间的 iframe 跨域)的完美跨域方法。
但官方针对服务端和客户端分离的跨域情形进行了说明:
