如何在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
相关产品推荐
相关产品推荐

