You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

德语字符URL编码异常:为何ü编码结果为%fc而非%C3%BC?

自定义UrlEncode函数编码异常分析

问题描述

我编写了如下SQL Server自定义UrlEncode函数,通过遍历字符串对字符进行编码:

CREATE FUNCTION [dbo].[UrlEncode](@url nvarchar(MAX))
    RETURNS nvarchar(3072)
AS
BEGIN
    DECLARE @c nchar(1);
    DECLARE @count int = LEN(@url);
    DECLARE @i int = 1;
    DECLARE @urlReturn nvarchar(max) = '';

    WHILE (@i <= @count)
    BEGIN
        SET @c = SUBSTRING(@url, @i, 1);
    
        IF @c LIKE N'[A-Za-z0-9()''*\-._!~]' COLLATE Latin1_General_BIN ESCAPE N'\' COLLATE Latin1_General_BIN
        BEGIN
            SET @urlReturn = CONCAT(@urlReturn, @c);
        END
        ELSE
        BEGIN
            SET @urlReturn = CONCAT(@urlReturn, '%',
                SUBSTRING(sys.fn_varbintohexstr(CAST(@c AS varbinary(MAX))), 3, 2),
                ISNULL(NULLIF(SUBSTRING(sys.fn_varbintohexstr(CAST(@c AS varbinary(MAX))), 5, 2), '00'), ''));
        END
    
        SET @i = @i +1;
     END

    RETURN @urlReturn;
END

执行语句 SELECT dbo.UrlEncode('ü') 后,得到的结果是 %fc,但正确的URL编码结果应为 %C3%BC,请问问题出在哪里?

原因分析

问题核心在于字符编码的转换逻辑不符合URL编码标准:

  • SQL Server中nvarchar类型的字符以UTF-16编码存储,直接将nchar(1)的'ü'转为varbinary时,得到的是UTF-16编码值0xFC00,函数截取后两位FC,最终输出%fc。
  • 标准URL编码要求将字符转换为UTF-8编码后,再对每个字节进行十六进制编码。'ü'的UTF-8编码是两个字节0xC3和0xBC,因此正确结果应为%C3%BC。

修正方案

需要修改函数逻辑,先将字符转换为UTF-8编码的二进制数据,再遍历每个字节进行编码,而非直接处理UTF-16的单个字符:

CREATE FUNCTION [dbo].[UrlEncode](@url nvarchar(MAX))
    RETURNS nvarchar(MAX)
AS
BEGIN
    DECLARE @utf8Bytes varbinary(MAX) = CONVERT(varbinary(MAX), @url, 65001); -- 转换为UTF-8编码的二进制
    DECLARE @len int = DATALENGTH(@utf8Bytes);
    DECLARE @i int = 1;
    DECLARE @urlReturn nvarchar(MAX) = '';
    DECLARE @byte tinyint;

    WHILE (@i <= @len)
    BEGIN
        SET @byte = SUBSTRING(@utf8Bytes, @i, 1);
        
        -- 判断是否为URL安全字符(对应ASCII范围的安全字符)
        IF (@byte BETWEEN 0x41 AND 0x5A) -- A-Z
            OR (@byte BETWEEN 0x61 AND 0x7A) -- a-z
            OR (@byte BETWEEN 0x30 AND 0x39) -- 0-9
            OR (@byte IN (0x28, 0x29, 0x27, 0x2A, 0x2D, 0x2E, 0x5F, 0x21, 0x7E)) -- ()'*-._!~
        BEGIN
            SET @urlReturn = CONCAT(@urlReturn, CHAR(@byte));
        END
        ELSE
        BEGIN
            -- 将字节转为十六进制,拼接%前缀
            SET @urlReturn = CONCAT(@urlReturn, '%', UPPER(sys.fn_varbintohexstr(@byte)));
        END
    
        SET @i = @i + 1;
    END

    RETURN @urlReturn;
END

关键改动说明

  1. 使用CONVERT(varbinary(MAX), @url, 65001)将nvarchar字符串转换为UTF-8编码的二进制数据(65001是SQL Server中UTF-8的编码页编号)。
  2. 遍历UTF-8二进制数据的每个字节,而非原字符串的单个UTF-16字符,确保多字节UTF-8字符被正确拆分编码。
  3. 直接对每个字节进行安全判断和编码,符合URL编码的标准逻辑。

执行修正后的函数 SELECT dbo.UrlEncode('ü'),将得到正确结果 %C3%BC。

内容的提问来源于stack exchange,提问作者Ivan Debono

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:07:53