Delphi TWebBrowser - как использовать прокси с логином/паролем?

Я хочу использовать Delphi VCL-компонент TWebBrowser с прокси. Кажется, довольно легко сделать что-то вроде этого:

var PIInfo: PInternetProxyInfo;
begin
  PIInfo^.dwAccessType := INTERNET_OPEN_TYPE_PROXY;
  PIInfo^.lpszProxy := PAnsiChar('proxyserver.com:8888');
  PIInfo^.lpszProxyBypass := PAnsiChar('');
  UrlMkSetSessionOption(INTERNET_OPTION_PROXY, PIInfo, SizeOf(Internet_Proxy_Info), 0);
end;

Но я также хотел бы использовать прокси с аутентификацией. И тут у меня случилась беда. Я узнал, что можно установить имя прокси и пароль с помощью функции WinAPI InternetSetOption, пример ниже:

var UserName: AnsiString;
    ConnectionHandle: HINTERNET;
begin
  // Init ConnectionHandle here 
  //... 
  res := InternetSetOption(ConnectionHandle, 
                           INTERNET_OPTION_PROXY_USERNAME,  
                           UserName, 
                           Length(UserName) + 1);
end;

Я узнал, что InternetSetOption с такими параметрами, как INTERNET_OPTION_PROXY_USERNAME, может применяться только к дескриптору Интернета, созданному такими функциями, как InternetConnect или HttpOpenRequest.

Ответ об этом можно найти здесь.

Это не проблема, я могу сначала позвонить в InternetConnect. Но после привязки этого интернет-дескриптора к моему TWebBrowser кажется невозможным. TWebBrowser проигнорирует эти настройки, потому что они применяются к конкретному выделенному дескриптору Интернета.

Итак, мой вопрос: можно ли настроить прокси с аутентификацией в Delphi-коде, чтобы использовать его из TWebBrowser?

ПС. Альтернативным вариантом является запоминание настроек прокси-сервера логина/пароля, когда TWebBrowser запрашивает их, но у меня есть несколько логинов/паролей, поэтому я хотел бы настроить их из кода.

Спасибо заранее.


person Ivkin Igor    schedule 19.04.2017    source источник
comment
microsoft.public.inetsdk.programming.webbrowser-ctl.narkive.com/   -  person David Heffernan    schedule 19.04.2017
comment
К вашему сведению, ваш первый фрагмент кода неверен. Вы объявляете неинициализированный указатель, который ни на что не указывает. Вместо этого вам нужно использовать это: var IInfo: InternetProxyInfo; begin IInfo.dwAccessType := INTERNET_OPEN_TYPE_PROXY; ... UrlMkSetSessionOption(INTERNET_OPTION_PROXY, @IInfo, SizeOf(IInfo), 0); end;   -  person Remy Lebeau    schedule 19.04.2017
comment
Реми Лебо, да, именно так. На самом деле я забыл добавить в этот фрагмент еще и код: New(PIInfo); ..... Распоряжаться (PInfo);   -  person Ivkin Igor    schedule 21.04.2017


Ответы (1)


Комментарий Дэвида Хеффернана заставил меня пойти в правильном направлении. Отвечая на мой собственный вопрос, на случай, если кто-то будет искать ответ, я нашел три решения этой проблемы.

Все фрагменты кода доступны для Delphi XE4.

<сильный>1. Использование обработчика событий в TWebBrowser.

TWebBrowser имеет событие OnBeforeNavigate2. Процедура этого метода содержит поле Headers. Таким образом, мы можем определить некоторый метод, например:

procedure TForm1.WebBrowser1BeforeNavigate2(ASender: TObject; 
                                            const pDisp: IDispatch;
                                            const URL: OleVariant;
                                            const Flags: OleVariant;
                                            const TargetFrameName: OleVariant;
                                            const PostData: OleVariant;
                                            const Headers: OleVariant;
                                            var Cancel: WordBool);
var aHeaders: OleVariant;
begin
  if ASender = WebBrowser1 then begin
    if ALPos('X-StopHandling', Headers) <= 0 then begin
      aHeaders := Headers + 'Proxy-Authorization: BASIC BASE64_of_login_and_password' + #13#10 +
                            'X-StopHandling: 1' + #13#10;
      WebBrowser1.Navigate2(URL, Flags, TargetFrameName, PostData, aHeaders);
      Cancel := true;
    end;
  end;
end;

... и после применить его к веб-браузеру...

WebBrowser1.OnBeforeNavigate2 := WebBrowser1BeforeNavigate2;

Этот метод основан на использовании заголовка Proxy-Authorization, который позволяет определить учетные данные прокси для запроса. Также потребуется сначала установить прокси-сервер и порт, используя UrlMkSetSessionOption, как указано в первом посте.

<сильный>2. Использование параметра заголовков в методе Navigate2

Метод Navigate2 TWebBrowser поддерживает параметр Headers. Таким образом, мы можем определить тот же заголовок Proxy-Authorization при вызове этого метода. Проблема этого способа в том, что все внутренние вызовы Navigate2 (например, если какой-то Javascript на странице будет вызывать что-то через AJAX) будут проходить без этого заголовка.

Первое решение лишено этого недостатка.

Фрагмент кода здесь:

var EmptyParam: OleVariant;
    //...
begin

  // init proxy server and port first as described in the first post
  EmptyParam := System.Variants.EmptyParam;
  WebBrowser1.Navigate2('http://something', 
                        EmptyParam{Flags}, 
                        EmptyParam{TargetFrameName}, 
                        EmptyParam{PostData}, 
                        'Proxy-Authorization: ...' + #13#10);
end;

<сильный>3. Использование альтернативного компонента

Я нашел реализацию Chromium для Delphi (в активной разработке) — CEF4Delphi. Он был основан на библиотеке DCEF3, от которой, кажется, осталось немного.

Он поддерживает интерфейс настроек прокси из коробки. Можно определить прокси-сервер, порт, имя пользователя и пароль, используя базовые свойства объекта основного браузера.

Так что в случае, если использование TWebBrowser не обязательно для ваших целей, вы можете взглянуть на этот компонент.

person Ivkin Igor    schedule 21.04.2017