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

如何在TIdHTTPServer的OnCommandGet事件中设置AuthRealm的Unicode字符?

解决TIdHTTPServer中AuthRealm Unicode字符的响应头处理问题

我懂你碰到的麻烦了——直接给AuthRealm赋值Unicode俄文字符后,响应头里的内容并没有正确显示,哪怕已经设置了IOHandler的编码。这是因为Indy默认不会自动处理HTTP认证头中Realm字段的Unicode编码,HTTP头的编码规则和响应内容是分开的。

问题根源

HTTP协议早期的WWW-Authenticate头字段要求Realm值使用ISO-8859-1编码,对于Unicode字符,需要按照RFC 5987的标准进行编码(或者使用URL编码),而Indy的AuthRealm属性默认不会自动做这个转换,所以直接赋值Unicode字符串会导致乱码或者无法正确解析。

解决方案

这里有两种可靠的处理方式:

方法1:使用URL编码处理Realm字符串

借助TIdURI.URLEncode方法将Unicode的Realm字符串转换成UTF8编码的URL格式,再赋值给AuthRealm:

procedure TMainForm.HttpServerCommandGet(Context: TIdContext; RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
resourcestring
  DefaultPage = '<!DOCTYPE html>' + sLineBreak + '<title>Embedded Web Server</title>' + sLineBreak + '<h1>Embedded Web Server</h1>' + sLineBreak + '<p>Приветствие!' + sLineBreak + '<br>Это веб-страница, которая отображается по умолчанию.</p>' ;
const
  AuthRealmText = 'Аутентификация пользователя';
begin
  if UserHandle = IdUserHandleNone then
    if not RequestInfo.AuthExists or (UserManager.AuthenticateUser(RequestInfo.AuthUsername, RequestInfo.AuthPassword, UserHandle) < 0) then
    begin
      // 对Realm字符串进行UTF8 URL编码
      ResponseInfo.AuthRealm := TIdURI.URLEncode(AuthRealmText, IndyTextEncoding_UTF8);
      ResponseInfo.ContentText := 'Несанкционированный доступ запрещен!';
      ResponseInfo.ContentType := 'text/plain; charset=utf-8';
      Exit
    end;
  if RequestInfo.Document = '/' then
  begin
    ResponseInfo.ContentText := DefaultPage;
    ResponseInfo.ContentType := 'text/html; charset=utf-8'
  end
end;

方法2:手动构建WWW-Authenticate响应头

如果想更严格遵循RFC 5987的编码格式,可以直接设置自定义响应头,绕过AuthRealm属性:

procedure TMainForm.HttpServerCommandGet(Context: TIdContext; RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
resourcestring
  DefaultPage = '<!DOCTYPE html>' + sLineBreak + '<title>Embedded Web Server</title>' + sLineBreak + '<h1>Embedded Web Server</h1>' + sLineBreak + '<p>Приветствие!' + sLineBreak + '<br>Это веб-страница, которая отображается по умолчанию.</p>' ;
const
  AuthRealmText = 'Аутентификация пользователя';
var
  EncodedRealm: string;
begin
  if UserHandle = IdUserHandleNone then
    if not RequestInfo.AuthExists or (UserManager.AuthenticateUser(RequestInfo.AuthUsername, RequestInfo.AuthPassword, UserHandle) < 0) then
    begin
      // 按照RFC 5987格式编码Realm
      EncodedRealm := 'UTF-8''''' + TIdURI.URLEncode(AuthRealmText, IndyTextEncoding_UTF8);
      // 添加自定义WWW-Authenticate头
      ResponseInfo.CustomHeaders.AddValue('WWW-Authenticate', Format('Basic realm="%s"', [EncodedRealm]));
      ResponseInfo.ContentText := 'Несанкционированный доступ запрещен!';
      ResponseInfo.ContentType := 'text/plain; charset=utf-8';
      ResponseInfo.ResponseNo := 401; // 确保返回401未授权状态码
      Exit
    end;
  if RequestInfo.Document = '/' then
  begin
    ResponseInfo.ContentText := DefaultPage;
    ResponseInfo.ContentType := 'text/html; charset=utf-8'
  end
end;

补充说明

你之前在OnConnect事件里设置的Context.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8,这个是用来处理响应内容的编码(比如HTML、文本内容),但HTTP响应头的编码规则是独立的,所以对AuthRealm的处理没有帮助。

内容的提问来源于stack exchange,提问作者Mega WEB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:56:51