博客 (120)

在 Linux 上运行 .NET 网站,通过

HttpContext.Connection.RemoteIpAddress

获取客户端的 IP 地址,结果是

::ffff:127.0.0.1

解决方法:

打开 Program.cs 文件,在 var app = builder.Build(); 之前(尽量往前)添加以下代码:

if (OperatingSystem.IsLinux())
{
    builder.Services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor
                                    | ForwardedHeaders.XForwardedProto
                                    | ForwardedHeaders.XForwardedHost;

        // 清除 KnownNetworks 和 KnownProxies,表示信任来自本机的代理(如 Nginx)
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });

    Console.WriteLine("ForwardedHeaders enabled (Running on Linux)");
}

然后在 app.UseRouting(); 之前添加以下代码:

if (OperatingSystem.IsLinux())
{
    app.UseForwardedHeaders();
    Console.WriteLine("UseForwardedHeaders() applied.");
}

其中,OperatingSystem.IsLinux() 用于判断只在 Linux 环境中生效,你可以视自身情况作判断。

xoyozo 7 天前
717

.NET 项目发布到 Linux / CentOS / nginx 上,调用 RedirectToAction 方法跳转到 127.0.0.1:443,而不是正在访问的域名,怎么办?

打开该网站的 nginx 配置文件,找到反射代理配置(proxy_pass),将:

proxy_set_header Host 127.0.0.1:$server_port;

改为

proxy_set_header Host $host;


xoyozo 7 天前
700

早前记录过在 CentOS 中部署 ASP.NET Core 网站,现在宝塔面板已经直接支持创建 .NET 网站了,再次记录一下。


本文环境:VS2022、.NET 9、宝塔面板v11。


一、在 VS 中创建一个 .NET 9 网站,项目名称例:WebApplication1

发布选项:

image.png

关于“生成单个文件”选项,若勾选,发布后的项目启动文件不带后缀名(.dll),尝试在宝塔面板 v11.0.0 中无法顺利启动。


二、在 Linux 服务器上创建目录:/www/wwwroot/WebApplication1/

将发布后的文件上传到这个目录上,最终的文件结构如下:

image.png


三、进入宝塔面板,在 网站-Net项目 中安装 .Net环境管理,这里以 9.0.201 为例:

image.png


四、添加项目

项目名称:随意

运行路径:项目所在目录,本例中为:

/www/wwwroot/WebApplication1

启动命令:使用 dotnet 命令,dotnet 命令可以不使用全路径(/www/server/dotnet/9.0.201/dotnet),第一个参数是项目启动文件,--urls 是反向代理的服务器和端口。服务器名可以是*也可以是localhost。例:

dotnet WebApplication1.dll --urls=http://*:5000

项目端口:与启动命令中的端口号一致

开机启动:一般会勾选

启动用户:尽量用 www,最小权限原则。

image.png

正常情况下,网站已启动,如果未启动,检查配置,根据报错内容排查问题。


五、配置网站

添加域名、SSL 证书等。


友情提示:

  • 网站版本更新重新发布后,需要手动重启网站才能生效,习惯于发布到 IIS(会自动生效)的同学要特别注意。

  • 新手尽量以空项目或默认项目来部署,避免因特殊原因导致一系列其它问题。

  • nginx 反向代理并不会转发所有 Header,需要手动配置。

xoyozo 14 天前
2,100

nginx.conf 中使用 resolver 设置了 DNS 后,nginx 会遵循这个指令,而不是直接使用系统的 hosts 配置。

所以,如果 resolver 设置了外部 DNS(譬如一般的公共 DNS),在 access_by_lua_block 中使用 resty.http 库发起对包含域名的网址的请求,会忽略 hosts 的设置。

解决方案:

1、修改 resolver 指向为本机 DNS。(AI 推荐,实测无效,可以研究一下配合 dnsmasq 使读取 hosts)

查看本机 DNS 的命令:

cat /etc/resolv.conf


nmcli dev show | grep DNS

2、request_uri 中直接请求带 IP 地址的网址。

要求这个网站允许直接使用 IP 地址访问。

需要禁用 SSL 验证(ssl_verify = false)。

xoyozo 半个月前
1,724

IIS 中使用 HttpPlatformHandler 模块部署 python web 项目时遇到 502.3 网关错误

HTTP 错误 502.3 - Bad Gateway

There was a connection error while trying to route the request.

最可能的原因:

  • CGI 应用程序没有返回一组有效的 HTTP 错误。

  • 由于父网关中出现错误,充当代理或网关的服务器无法处理该请求。

可尝试的操作:

  • 使用 DebugDiag 排查 CGI 应用程序。

  • 确定此错误是否由代理或网关引起。

详细错误信息:

模块    httpPlatformHandler

通知    ExecuteRequestHandler

处理程序    httpplatformhandler

错误代码    见下方表格

详细信息:

当 CGI 应用程序未返回一组有效的 HTTP 头,或者代理或网关无法将请求发送至父网关时,便会出现此错误。您可能需要获取一个网络跟踪,或者与代理服务器管理员联系(如果不是 CGI 的问题)。

错误代码可能的错误原因
0x8007053d未安装相关组件库,建议执行命令:pip install -r requirements.txt
0x80070005

若显示配置错误“由于权限不足而无法读取配置文件”则是应用代码目录未配置相应用户的读取权限;

访问受限,请正确配置 IIS 中的网站凭据、应用程序池标识、项目目录“读取”、解释器目录“读取和执行”权限等

0x80072ee2执行超时,一般发生在批量读写的时候
0x8007042b
任何错误

查看日志文件。

可能的错误原因:

  • 编码问题:强制使用 utf-8


xoyozo 3 个月前
719
  1. 临界区与 lock 关键字

    核心作用:

    通过将多线程访问串行化,保护共享资源或代码段。lock 关键字是 Monitor 类的语法糖,提供异常安全的临界区实现。

    实现示例:

    // 创建私有静态只读对象
    // private static readonly object _lockObj = new object();
    private static readonly System.Threading.Lock _locker = new(); // .NET 9+ 推荐使用 Lock 类型,避免传统 object 的性能损耗
    
    public void ThreadSafeMethod()
    {
        lock (_lockObj) 
        {
            // 临界区代码(每次仅一个线程可进入)
        }
    }

    超时机制:

    高并发场景可结合 Monitor.TryEnter 设置超时,避免无限等待:


    if (Monitor.TryEnter(lockObject, TimeSpan.FromSeconds(1)))
    {
        try { /* 操作 */ }
        finally { Monitor.Exit(lockObject); }
    }

    关键特性:

    用户态锁(无内核切换开销)

    自动调用Monitor.Enter和Monitor.Exit

    必须使用专用私有对象作为锁标识

    注意事项:

    ❌ 避免锁定this、Type实例或字符串(易引发死锁)

    ❌ 避免嵌套锁(需严格按顺序释放)

    ✅ 推荐readonly修饰锁对象

    ❌ lock 不适用于异步代码(async/await),需使用 SemaphoreSlim 实现异步锁

    lock 示例

     

  2. 互斥锁(Mutex)

    核心作用:

    系统级内核锁,支持跨进程同步,但性能开销较高(用户态/内核态切换)。

    实现示例:

    using var mutex = new Mutex(false, "Global\\MyAppMutex");
    
    try 
    {
        // 等待锁(最大等待时间500ms)
        if (mutex.WaitOne(500)) 
        {
            // 临界区代码
        }
    }
    finally 
    {
        if (mutex != null)
        {
            mutex.ReleaseMutex();
        }
    }

    关键特性:

    支持跨应用程序域同步

    线程终止时自动释放锁

    支持命名互斥体(系统全局可见)

    适用场景:

    单实例应用程序控制

    进程间共享文件访问

    硬件设备独占访问

    Mutex 示例

     

  3. 信号量(Semaphore)

    核心作用:

    通过许可计数器控制并发线程数,SemaphoreSlim为轻量级版本(用户态实现)。

    实现对比:

    类型
    跨进程
    性能
    最大许可数
    Semaphore
    ✔️

    系统限制
    SemaphoreSlim


    Int32.Max

    代码示例:

    // 创建初始3许可、最大5许可的信号量
    var semaphore = new SemaphoreSlim(3, 5);
    
    semaphore.Wait();  // 获取许可
    try 
    {
        // 资源访问代码
    }
    finally 
    {
        semaphore.Release();
    }

    异步编程

    private readonly SemaphoreSlim _asyncLock = new(1, 1);
    public async Task UpdateAsync()
    {
        await _asyncLock.WaitAsync();
        try { /* 异步操作 */ }
        finally { _asyncLock.Release(); }
    }

    典型应用:

    数据库连接池(限制最大连接数)

    API 请求限流

    批量任务并发控制

    Semaphore 示例

     

  4. 事件(Event)

    核心机制:

    通过信号机制实现线程间通知,分为两种类型:

    类型
    信号重置方式
    唤醒线程数
    AutoResetEvent
    自动
    单个
    ManualResetEvent
    手动
    所有

    使用示例:

    var autoEvent = new AutoResetEvent(false);
    
    // 等待线程
    Task.Run(() => 
    {
        autoEvent.WaitOne();
        // 收到信号后执行
    });
    
    // 信号发送线程
    autoEvent.Set();  // 唤醒一个等待线程

    高级用法:

    配合WaitHandle.WaitAll实现多事件等待

    使用ManualResetEventSlim提升性能

    AutoResetEvent 示例

     

  5. 读写锁(ReaderWriterLockSlim)

    核心优势:

    实现读写分离的并发策略,适合读多写少场景(如缓存系统)。

    锁模式对比:

    模式
    并发性
    升级支持
    读模式(EnterReadLock)
    多线程并发读

    写模式(EnterWriteLock)
    独占访问

    可升级模式
    单线程读→写
    ✔️

    代码示例:

    var rwLock = new ReaderWriterLockSlim();
    
    // 读操作
    rwLock.EnterReadLock();
    try 
    {
        // 只读访问
    }
    finally 
    {
        rwLock.ExitReadLock();
    }
    
    // 写操作
    rwLock.EnterWriteLock();
    try 
    {
        // 排他写入
    }
    finally 
    {
        rwLock.ExitWriteLock();
    }

    最佳实践:

    优先使用ReaderWriterLockSlim(旧版有死锁风险)

    避免长时间持有读锁(可能饿死写线程)

    ReaderWriterLockSlim 示例

  6. 原子操作(Interlocked)

    原理:

    通过CPU指令实现无锁线程安全操作。

    常用方法:

    int counter = 0;
    Interlocked.Increment(ref counter);      // 原子递增
    Interlocked.Decrement(ref counter);      // 原子递减
    Interlocked.CompareExchange(ref value, newVal, oldVal);  // CAS操作

    适用场景:

    简单计数器

    标志位状态切换

    无锁数据结构实现

     

  7. 自旋锁(SpinLock)

    核心特点:

    通过忙等待(busy-wait)避免上下文切换,适用极短临界区(<1微秒)。

    实现示例:

    private SpinLock _spinLock = new SpinLock();
    
    public void CriticalOperation()
    {
        bool lockTaken = false;
        try 
        {
            _spinLock.Enter(ref lockTaken);
            // 极短临界区代码
        }
        finally 
        {
            if (lockTaken) _spinLock.Exit();
        }
    }

    优化技巧:

    单核CPU需调用Thread.SpinWait或Thread.Yield

    配合SpinWait结构实现自适应等待

     

  8. 同步机制对比指南

    机制
    跨进程
    开销级别
    最佳适用场景
    lock


    通用临界区保护
    Mutex
    ✔️

    进程间资源独占
    Semaphore
    ✔️

    并发数限制(跨进程)
    SemaphoreSlim


    并发数限制(进程内)
    ReaderWriterLockSlim


    读多写少场景
    SpinLock

    极低
    纳秒级临界区
    Interlocked
    -无锁
    简单原子操作

选择原则:

  1. 优先考虑用户态锁(lock/SpinLock/SemaphoreSlim)

  2. 跨进程需求必须使用内核对象(Mutex/Semaphore)

  3. 读写比例超过10:1时考虑读写锁

  4. 自旋锁仅用于高频短操作(如链表指针修改)

通过以上结构化的分类和对比,开发者可以更精准地选择适合特定场景的线程同步方案。建议在实际使用中配合性能分析工具(如BenchmarkDotNet)进行量化验证。

💡 ASP.NET 的异步编程(async/await)本质是单进程内的线程调度,不算“跨进程”。每个 IIS 应用程序池对应一个独立的工作进程(w3wp.exe),不同用户访问同一应用程序池下的 ASP.NET 网站,两者的请求均由同一个 w3wp.exe 进程处理。可能跨进程的场景有:Web Garden 配置、多应用程序池部署等。

在 C# 中,除了常规锁机制(如 lock、Mutex、Semaphore 等),还有一些内置类型通过内部锁或无锁设计实现线程安全。以下是常见的几类:

  1. 线程安全集合(System.Collections.Concurrent)这些集合通过细粒度锁或无锁算法(如 CAS)实现线程安全,适合高并发场景。

    • ConcurrentDictionary:分段锁机制,将数据分片存储,每个分片独立加锁,减少锁竞争。

    • ConcurrentQueue / ConcurrentStack基于原子操作(Interlocked)保证线程安全。

    • ConcurrentBag:每个线程维护本地存储,减少争用,适合频繁添加和移除的场景。

    • BlockingCollection:基于 ConcurrentQueue 和信号量(SemaphoreSlim)实现生产-消费者模式,支持阻塞和超时。

  2. 不可变集合(System.Collections.Immutable) 通过数据不可变性实现线程安全(无需锁),每次修改返回新对象。

  3. Lazy 的线程安全初始化(Lazy<T>) 通过锁或 Interlocked 确保延迟初始化的线程安全。

  4. 通道(System.Threading.Channels)用于异步生产-消费者模型,内部通过锁和信号量管理容量限制。

  5. 内存缓存(System.Runtime.Caching.MemoryCache)内部使用锁保护共享状态,确保线程安全。

  6. 原子操作类型(Interlocked 类、Volatile 关键字、Unsafe 类)通过 CPU 指令实现无锁线程安全。

  7. 其他同步工具(Barrier、CountdownEvent)虽然不是严格意义上的锁,但用于协调线程。

xoyozo 4 个月前
1,158

在 .NET Framework 的缓存管理中,cacheMemoryLimitMegabytes 是一个关键配置属性,用于控制内存缓存(MemoryCache)实例的最大内存占用。以下是其具体用法及实现细节:

  1. 基本定义与作用

    • 功能:通过 cacheMemoryLimitMegabytes 可设置 MemoryCache 实例允许占用的最大内存(单位:MB)。若缓存数据超过此限制,系统会自动淘汰旧条目。

    • 默认值:默认值为 0,表示缓存基于计算机的物理内存自动管理(例如根据可用内存动态调整)。

  2. 配置方式

    • 通过配置文件(web.config)

      在 web.config 的 <system.runtime.caching> 节点下配置 namedCaches,示例:

      <configuration>
        <system.runtime.caching>
          <memoryCache>
            <namedCaches>
              <add 
                name="Default" 
                cacheMemoryLimitMegabytes="500" 
                physicalMemoryLimitPercentage="50" 
                pollingInterval="00:05:00" />
            </namedCaches>
          </memoryCache>
        </system.runtime.caching>
      </configuration>

      参数说明:

      • cacheMemoryLimitMegabytes:最大内存限制(例如 500 表示 500MB)。

      • physicalMemoryLimitPercentage:允许使用的物理内存百分比(可选)。

      • pollingInterval:缓存清理策略的轮询间隔(例如每5分钟检查一次)。

    • 通过代码动态配置

      在初始化 MemoryCache 时,通过 NameValueCollection 传递参数:

      var config = new NameValueCollection
      {
          { "cacheMemoryLimitMegabytes", "500" },
          { "physicalMemoryLimitPercentage", "50" },
          { "pollingInterval", "00:05:00" }
      };
      var cache = new MemoryCache("CustomCache", config);

      此方式适用于需要动态调整缓存策略的场景。

  3. 注意事项

    • 优先级规则:

      若同时配置了 cacheMemoryLimitMegabytes 和 physicalMemoryLimitPercentage,系统会选择两者中较小的值作为限制。

    • 分布式缓存兼容性:

      此属性仅适用于进程内缓存(如 MemoryCache),若使用 Redis 等分布式缓存需通过其独立配置管理内存。

    • 监控与调试:

      建议结合性能计数器(如 ASP.NET Applications 类别下的 Cache Total Entries)或日志记录模块(参考 web.config 的 <system.diagnostics> 配置)监控实际内存占用。

  4. 应用场景示例

    场景:一个电商网站需要缓存商品目录数据,限制最大内存为 1GB。

    配置实现:

    <add 
      name="ProductCatalogCache" 
      cacheMemoryLimitMegabytes="1024" 
      pollingInterval="00:10:00" />

    代码调用:

    var productCatalog = MemoryCache.Default["ProductCatalog"];
  5. 常见问题

    1. Q:设置为 0 时缓存会无限制增长吗?

      A:不会。此时缓存基于系统物理内存动态管理,通常上限为总内存的 70%-90%。

    2. Q:如何验证配置已生效?

      A:可通过 MemoryCache.GetCount() 统计条目数量,或使用性能监视器跟踪内存占用。

xoyozo 5 个月前
634
数据库 数据类型 收费情况 调用方式 数据来源 资料
BaoStock 仅提供历史数据(如日线、周线),无实时行情 免费开源 Python 数据来源为交易所或合作机构的标准化接口 文档
AkShare 股票、期货、债券、期权、外汇、货币、指数…… 免费开源 Python / Anaconda / R / MATLAB / 本地 Web API

基于爬虫技术从大型财经网站抓取公开数据

包含北交所行情数据                

文档 / 数据字典 / AKTools
Tushare Pro 股票、指数、公募、期货、期权、债券、外汇、港股、美股…… 免费 / 收费 Web API / Python / Matlab / R

通过社区的采集和整理存入数据库经过质量控制后再提供给用户

包含北交所行情数据                

积分 / 权限 / 文档
麦蕊智数 沪深股票基础数据、实时交易数据、指数数据 免费 / 收费 Web API licence / 文档
JoinQuant/JQData 股票、基金等行情数据 试用 / 收费 Python 文档
xoyozo 6 个月前
1,392
  1. 国家智慧教育公共服务平台 https://gjzwfw.www.gov.cn/

  2. 中国裁判文书网 https://wenshu.court.gov.cn/

  3. 国家企业信用信息公示系统 https://gs.gsxt.gov.cn/

  4. 国家社会保险服务平台 https://si.12333.gov.cn/

  5. 天地图 https://www.tianditu.gov.cn/

  6. 国家统计局 https://www.stats.gov.cn/

  7. 中国商标网 https://sbj.cnipa.gov.cn/sbj/

  8. 国家法律法规数据库 https://flk.npc.gov.cn/

  9. 中国专利公布公告网 http://epub.cnipa.gov.cn/

  10. 国家标准全文公开系统 https://openstd.samr.gov.cn/bzgk/gb/

  11. 国家药品监督管理局 https://www.nmpa.gov.cn/datasearch/

  12. 食品安全抽检公布结果查询系统 https://spcjsac.gsxt.gov.cn/

  13. 发票查验平台 http://inv-veri.chinatax.gov.cn/

  14. 中国关键词 http://keywords.china.org.cn/

  15. 工信部申诉受理中心 https://ythzxfw.miit.gov.cn/

  16. 合同示范文本库 https://htsfwb.samr.gov.cn/

  17. 中国法律服务网 https://www.12348.gov.cn/

  18. 中国庭审公开网 https://tingshen.court.gov.cn/

非 gov 网站

  1. 终身教育平台 https://le.ouchn.cn/

  2. 国家数字图书馆 https://www.nlc.cn/

  3. 国家哲学社会科学文献 https://www.ncpssd.cn/

  4. 国家高等教育智慧教育平台 https://www.chinaooc.com.cn/

  5. 职业教育专业教学资源库 https://zyk.icve.com.cn/


转自 一网一匠 9 个月前
1,025

本文仅针对自己遇到的情况进行整理,并不完善,仅供参考。

微信图片_20250112102607.jpg

首先点击这个封禁页面上的“客服指引”,在“微信访问网站被限制的相关问题”页面上找到反馈邮箱 moment@tencent.com,按规定格式给这个邮箱反馈情况,可以咨询具体被封禁的原因和网址等方便处理。几分钟后就能收到回信(即使是周末)。这次被告知是被手机管家拦截,并提供了另一个申述通道:http://gj.qq.com/online_server/complain_url.html。提交网址申述后等待3个工作日。

实际等了1个小时就收到回复了(即使是周末)。

微信图片_20250112110658.png

附:在线网址检测:https://urlsec.qq.com/check.html


xoyozo 9 个月前
1,286