本文环境:CentOS 7、nginx 1.16、ASP.NET Core 3.0
安装 nginx,可以使用宝塔面板。
创建网站,保证网站静态页面能够正常访问。
必要时配置 SSL 证书。
安装 ASP.NET Core 运行时:
安装说明见:https://dotnet.microsoft.com/download,切换到 Linux,选择 Install .NET Core Runtime
选择操作系统,按页面说明安装即可。
发布一个 ASP.NET Core 项目到网站目录,运行应用程序:
dotnet 应用的程序集文件名.dll
必须先 cd 到项目所在目录再执行,否则“Content root path”不会指向网站根目录,从而导致无法访问静态文件。
观察到端口为 5000(默认),该 Url 用于下一步设置反向代理。
配置 nginx 反向代理:(使用宝塔面板时建议使用面板中提供的“反向代理”功能)
location / { proxy_pass http://localhost:5000; }
查看官方详细说明:使用 Nginx 在 Linux 上托管 ASP.NET Core

本文使用 Pomelo 提供的 Pomelo.EntityFrameworkCore.MySql,如使用 MySql.Data.EntityFrameworkCore 请移步。
对比 MySql.Data.EntityFrameworkCore 与 Pomelo.EntityFrameworkCore.MySql
本文以 Visual Studio 2019、ASP.NET Core 3.0 开发环境为例。
新建 ASP.NET Core Web 应用程序。
安装 NuGet 包:
Microsoft.EntityFrameworkCore.Tools
Pomelo.EntityFrameworkCore.MySql(3.0.0 预发行版以上)
根据已有数据库创建数据模型。在 NuGet 的程序包管理(Package Manager)控制台中(PowerShell)执行命令:
Scaffold-DbContext "server=数据库服务器;uid=数据库用户名;pwd=数据库密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -OutputDir Data -Force
.Net Core CLi:
dotnet ef dbcontext scaffold "server=数据库服务器;uid=数据库用户名;pwd=数据库密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -o Data -f
搞定。
补充:其它数据库提供程序请参考:https://docs.microsoft.com/zh-cn/ef/core/providers/
代码参数说明:
-OutputDir (-o) *** 实体文件所存放的文件目录
-ContextDir *** DbContext文件存放的目录
-Context *** DbContext文件名
-Schemas *** 需要生成实体数据的数据表所在的模式
-Tables(-t) *** 需要生成实体数据的数据表的集合
-DataAnnotations
-UseDatabaseNames 直接使用数据库中的表名和列名(某些版本不支持)
-Force (-f) 强制执行,重写已经存在的实体文件
更多高级用法请参考官方文档。

打开项目文件,在 <ItemGroup /> 中添加一个 <DotNetCliToolReference />:(注意版本号)
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
结果:

微信的 H5 页面前端引导到:
https://api.magcloud.cc/magshare/{siteId}?jump_url={jump_url}&content_url={content_url}
各参数含义见官方文档:http://doc.magcloud.net/325339
content_url
地址(一般仍为活动页面)接收参数magshareredirect
,值为 1 则跳转到自定义的引导页。自定义引导页按 iOS 和安卓显示图文和箭头,引导用户点击右上角菜单,在浏览器中打开。
在浏览器 H5 中引导打开:
{siteId}://pagejump?jump_url={jump_url}
各参数含义见第 1 步中的文档。
这里涉及一个“若未安装则引导安装”的过程,可以选择下方合适的一种方式实现:
A
标签的href
填入下载地址,onclick
事件location
到 Apponclick
事件location
到 App,再用setTimeOut
location
到下载地址若仍无法实现预期效果,可以在弹出层中放置“未安装,前往下载”和“已安装,立即打开”两个按钮,让用户自己选择
若下载地址为应用宝,那么在 iOS 中可能会出现“打开 App 后继而自动打开 App Store”的情况,可以自建中转的 App 介绍页引导到 App Store 或应用宝。
分别实现微信和 MAGAPP 客户端的分享

型号 | 传输速率 | 带宽 | 类型 | 相对于上一类的优势 |
一类线(CAT1) | - | - | 非屏蔽/屏蔽 | 传输语音 |
二类线(CAT2) | 4Mbps | 1MHz | 非屏蔽/屏蔽 | 可传输数据 |
三类线(CAT3) | 10Mbps | 16MHz | 非屏蔽/屏蔽 | 速度提升 |
四类线(CAT4) | 16Mbps | 20MHz | 非屏蔽/屏蔽 | 速度提升 |
五类线(CAT5) | 100Mbps | 100MHz | 非屏蔽/屏蔽 | 增加密度、绝缘材料 |
超五类线(CAT5e) | 1Gbps | 100MHz | 非屏蔽/屏蔽 | 衰减小、串扰少 |
六类线(CAT6) | 1Gbps | 1~250MHz | 非屏蔽/屏蔽 | 全双工,改善串扰及回波损耗 |
超六类线(CAT6e) | 1Gbps? 10Gbps? | 200~250 MHz | 非屏蔽/屏蔽 | 改善串扰、衰减、信噪比等 |
七类线(CAT7) | 10Gbps | 500MHz+ | 屏蔽 | 适应万兆位以太网技术 |
八类线(CAT8) | 25Gbps、40Gbps | 屏蔽 |
普通家庭装修布线建议上到千兆网络(2019年),至少选择六类网线。

Orbi 型号命名规则:
套装:RBK
主体:RBR
分身:RBS、RBW 等
套装对比:
CPU | 高通 IPQ4019 四核 717MHz | 四核 710MHz | ||||
ROM | 128MB | - | - | - | - | - |
内存 RAM | 256MB DDR3 | 512MB | ||||
闪存 Flash | - | 256MB | 4GB | |||
包装内容 | 2 个(不分子母) | 1 个 RBR10 1 个 RBS10 | 1 个 RBR20 1 个 RBS20 | 1 个 RBR40 1 个 RBW30 插墙式 | 1 个 RBR40 1 个 RBS40 | 1 个 RBR50 1 个 RBS50 |
速度 | AC1300 双频段 1300Mbps 电力线 1000M 有线 | AC1200 双频段 2.4GHz 300Mbps+5GHz 866Mbps | 三频段 AC2200 本体 AC2200 分身 (866回程+866+400Mbps) | 三频段 AC3000 本体 AC3000 分身 (1733回程+866+400Mbps) | ||
本体端口 | 每个主机 3 个 WAN/LAN 自适应以太网端口 | 1 WAN & 1 LAN | 1 WAN & 1 LAN | 1 WAN & 3 LAN | 1 WAN & 3 LAN & 1 USB 2.0 | |
分身端口 | - | 2 LAN | - | 4 LAN | 4 LAN & 1 USB 2.0 | |
天线 | 4根 | 6根 | ||||
以太网回程 | 支持 | 支持 | ||||
Daisy Chain Topology 菊花链 | 支持 | |||||
Beamforming 波束成形 | 支持 | |||||
MU-MIMO | 支持 | |||||
802.11k/v 快速漫游 | 支持 | |||||
802.11r 快速漫游 | 不支持 | |||||
802.11ax(Wi-Fi 6) | 不支持 | |||||
AP 模式 | 不支持 | 支持 | ||||
关闭 WiFi 双频合一 | 原厂不支持,小米和 RBK50 可通过修改实现,分离后有线回程可能会失效 | |||||
IPv6 | 支持 | |||||
带机量 | 248 | |||||
覆盖范围 | - | 418 平方米 | 250 平方米 | 200 平方米 | 250 平方米 | 350 平方米 |
官网价 | 229.99 美元 | - | - | - | - | |
京东自营 | ||||||
京东旗舰店 | - | |||||
天猫旗舰店 | - | |||||
其它天猫店 | 969 苏宁易购 | - | RBK30:1288 | RBK40:1699 | - | |
优势 | 管理功能丰富。 配合米家APP 设置小米智能家居设备入网时,无需手动输入密码,入网更便捷。 网口盲插,不分子母。后续再扩展两个分身时可直接购买套装充当两个分身,相对于 Orbi 购买两个分身要节省成本。 | 三频。 性能稳定。 大内存 |
分体价格:
本体 RBR20:599
本体 RBR40:999
本体 RBR50:999 活动
分身 RBS20:699
分身 RBW30 插墙:999
分身 RBS40:1099
分身 RBS50:1449
分身 RBS50Y 室外:未知
价格采自2019年8月
主体/分身 匹配:
分身 RBS20 可作为 RBR20, RBR40 or RBR50 的卫星
分身 RBW30 可作为 RBR40 or RBR50 的卫星
分身 RBS40 可作为 RBR40 or RBR50 的卫星
分身 RBS50 可作为 RBR50 的卫星
分身 RBS50Y 可作为 RBR50 or RBR40 or SRR60 的卫星
RBK13 = 1个 RBR10 + 2个 RBS10
RBK20 = 1个 RBR20 + 1个 RBS20
RBK23 = 1个 RBR20 + 2个 RBS20
RBK30 = 1个 RBR40 + 1个 RBW30
RBK33 = 1个 RBR40 + 2个 RBW30
RBK40 = 1个 RBR40 + 1个 RBS40
RBK43 = 1个 RBR40 + 2个 RBS20
RBK44 = 1个 RBR40 + 3个 RBS20
RBK50 = 1个 RBR50 + 1个 RBS50
RBK53 = 1个 RBR50 + 2个 RBS50
扩展阅读:Mesh 路由器有线回程布线方案

本文介绍 ASP.NET 的 Swagger 部署,若您使用 ASP.NET Core 应用程序,请移步 ASP.NET Core Web API Swagger 官方文档:
https://github.com/domaindrivendev/Swashbuckle.AspNetCore
安装
NuGet 中搜索安装 Swashbuckle,作者 Richard Morris
访问
http://您的域名/swagger
配置
显示描述
以将描述文件(xml)存放到项目的 bin 目录为例:
打开项目属性,切换到“生成”选项卡
在“配置”下拉框选择“所有配置”
更改“输出路径”为:bin\
勾选“XML 文档文件”:bin\******.xml,(默认以程序集名称命名)
打开文件:App_Start/SwaggerConfig.cs
取消注释:c.IncludeXmlComments(GetXmlCommentsPath());
添加方法:
public static string GetXmlCommentsPath() { return System.IO.Path.Combine( System.AppDomain.CurrentDomain.BaseDirectory, "bin", string.Format("{0}.xml", typeof(SwaggerConfig).Assembly.GetName().Name)); }
其中 Combine 方法的第 2 个参数是项目中存放 xml 描述文件的位置,第 3 个参数即以程序集名称作为文件名,与项目属性中配置一致。
如遇到以下错误,请检查第 2、3、4 步骤中的配置(Debug / Release)
500 : {"Message":"An error has occurred."} /swagger/docs/v1
使枚举类型按实际文本作为参数值(而非转成索引数字)
打开文件:App_Start/SwaggerConfig.cs
取消注释:c.DescribeAllEnumsAsStrings();

之前已经介绍了百度编辑器在 ASP.NET 环境下的配置,本文继续补充改进其将图片等附件上传到阿里云 OSS。
首先从阿里云控制台下载相关 SDK,并阅读相关的 API 文档。链接:https://promotion.aliyun.com/ntms/act/ossdoclist.html
改造上传代码
打开文件 UploadHandler.cs,在 Process() 方法中找到:
File.WriteAllBytes(localPath, uploadFileBytes);
在其下方插入代码:
client.PutObject(bucketName, "upload/ueditor/" + savePath, localPath);
实现图标按钮上传和 HTML5 拖放上传。
PutObject() 的第 2 个参数是 OSS 中的图片路径,第 3 个参数是图片在网站目录下的磁盘路径。
打开文件 CrawlerHandler.cs,在 Fetch() 方法中找到:
File.WriteAllBytes(savePath, bytes);
在其下方插入代码:
client.PutObject(bucketName, "upload/ueditor/" + ServerUrl, savePath);
实现粘贴板图片上传。
同样注意两个参数变量。
修改路径前缀
上传成功后,编辑器会拼装路径到 HTML 代码中,这个前缀是在 config.json 文件中配置的,具体找到以 UrlPrefix
结尾的属性,如 imageUrlPrefix
,进行相应的修改即可:
"imageUrlPrefix": "//oss.xoyozo.net/upload/ueditor/", /* 图片访问路径前缀 */
路径以“//”开头能更好地兼容 https。

原标题:关于 PHP 获取 IP 地址的几种方法
PHP 获取客户端的 IP 地址有 4 种方式:
REMOTE_ADDR:浏览当前页面的用户计算机的 IP 地址
HTTP_X_FORWARDED_FOR:记录代理信息,会把每一层代理都记录
HTTP_CLIENT_IP:客户端的 IP
X-Real-IP:没有标准,由上一跳决定
REMOTE_ADDR 一般是不能伪造的,因为是通过服务器与客户端握手协议来获取的。而 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP 是在 header 信息里面,所以客户端是可以进行很轻松的伪造。下面是对这三种方式详解:
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 包含这样一行
代表请求由1.1.1.1
发出,经过三层代理,第一层是2.2.2.2
,第二层是3.3.3.3
,而本次请求的来源IP4.4.4.4
是第三层代理
而X-Real-IP
,没有相关标准,上面的例子,如果配置了X-Read-IP
,可能会有两种情况
所以 ,如果只有一层代理,这两个头的值就是一样的。
那一般在后端取值(比如 node.js 通过 nginx 代理)是用哪个值呢?我看 sf 上看一般推荐是用 X-Forwarded-For,直接用 X-Real-IP 岂不是更方便点?
X-Forwarded-For 确实是一般的做法
他在正向(如 squid)反向(如 nginx)代理中都是标准用法,而正向代理中是没有 x-real-ip 相关的标准的,也就是说,如果用户访问你的 nginx 反向代理之前,还经过了一层正向代理,你即使在 nginx 中配置了 x-real-ip,取到的也只是正向代理的 IP 而不是客户端真实 IP
大部分 nginx 反向代理配置文章中都没有推荐加上 x-real-ip ,而只有 x-forwarded-for,因此更通用的做法自然是取 x-forwarded-for
多级代理很少见,只有一级代理的情况下二者是等效的
如果有多级代理,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 为了符合有些用户会用代理,所以才首先使用了两个容易伪造的方法,如果有需要可以自行修改。
当微信支付的 notify_url
填写的是 https 的回调地址时,如果遇到支付成功但没有接收到回调的情况,可能是服务器开启了 SNI。
SNI,即服务器名称指示,用于在一台服务器上支持多个网站使用不同的 SSL 证书。
解决方案:
方法一、
notify_url
改为 http 的回调地址,缺点是容易被运营商 QJ,而且如果日后网站开启强制要求 https 访问就会使回调失败;方法二、【不推荐】可以为该网站单独配置一台服务,不使用 SNI,缺点是增加成本;
方法三、【推荐】该网站仍然“需要服务器名称指示”,在 IIS 中给默认网站(不是当前网站)添加一个 https 的域名绑定,不勾选“需要服务器名称指示”,证书随便选一个。缺点是时间一长容易忘记有这回事,不要轻易删除该绑定就好了,而且在网站搬迁的时候也同样要做该配置。
感谢 V2EX
