fcl-web/ru: what changed
Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.
Title: fcl-web/ru
| Old | New | Line | |
|---|---|---|---|
| 1 | + | ## Что такое fpWeb | |
| 2 | + | ||
| 3 | + | fpWeb можно использовать для создания приложений веб-сервера. Приложение веб-сервера может быть одним из следующих | |
| 4 | + | ||
| 5 | + | - Приложение CGI | |
| 6 | + | - Приложение FastCGI | |
| 7 | + | - Модуль Apache | |
| 8 | + | - Автономный HTTP-сервер, использующий компоненты HTTP-сервера Free Pascal. | |
| 9 | + | - Автономный сервер HTTP с использованием GNU libmicrohttp | |
| 10 | + | - Приложение Windows SysHTTP. | |
| 11 | + | ||
| 12 | + | Во всех случаях модель разработки одинакова: вы регистрируете обработчики для набора URL-адресов (называемых маршрутами), которые будет поддерживать ваше приложение. | |
| 13 | + | ||
| 14 | + | Затем вы встраиваете эти маршруты в одну из указанных выше сред: Это означает, что вы выбираете объект приложения, который будете использовать. | |
| 15 | + | ||
| 16 | + | В lazarus IDE у вас есть выбор приложений, когда вы запускаете новый проект. После запуска приложения можно изменить тип приложения, обычно это означает просто изменение имени модуля в разделе uses проекта. | |
| 17 | + | ||
| 18 | + | В одном двоичном файле можно поддерживать несколько сред, хотя это требует дополнительной работы. | |
| 19 | + | ||
| 20 | + | fpWeb также предлагает некоторую готовую поддержку для REST-сервера базы данных или для механизмов JSON RPC 2.0. Они построены поверх вышеупомянутой конструкции. Платформа Brook также построена на основе базовой архитектуры, описанной выше. | |
| 21 | + | ||
| 22 | + | Подробнее об этом можно прочитать в [[fpWeb Tutorial]] | |
| 23 | + | ||
| 24 | + | ## Использование fpWeb вместе с Lazarus | |
| 25 | + | ||
| 26 | + | ### Установка пакета weblaz fpWeb Lazarus | |
| 27 | + | ||
| 28 | + | Первым делом необходимо установить пакет, который находится по пути lazarus/components/fpweb/weblaz.lpk. Как обычно с пакетами времени разработки, вам придется пересобрать Lazarus. | |
| 29 | + | ||
| 30 | + | ### Создание CGI-приложения | |
| 31 | + | ||
| 32 | + | После установки пакета weblaz можно создать очень простое веб-приложение CGI, отображающее HTML-страницу, перейдя в меню Lazarus «Файл - Новый ...». Из списка возможных приложений выберите «Приложение CGI», как показано на изображении ниже, которое создаст основной файл проекта CGI и веб-модуль fpweb. | |
| 33 | + | ||
| 34 | + |  | |
| 35 | + | ||
| 36 | + | TFPWebModule позволяет вам управлять свойствами и событиями с помощью инспектора объектов. | |
| 37 | + | ||
| 38 | + | Чтобы добавить код для отображения страницы, необходимо добавить обработчик запроса. Для этого дважды щелкните свойство OnRequest в инспекторе объектов, как показано на изображении ниже: | |
| 39 | + | ||
| 40 | + |  | |
| 41 | + | ||
| 42 | + | В обработчике событий нужно написать HTML-код, который будет отображаться браузером. Чтобы избежать смешивания Pascal и HTML, эту страницу можно загружать из каталога, в котором находится исполняемый файл CGI, с помощью `AResponse.Contents.LoadFromFile()`. | |
| 43 | + | ||
| 44 | + | Тип ответа должен быть установлен в `AResponse.ContentType`. Для HTML-страниц это должно иметь значение 'text/html;charset=utf-8'. | |
| 45 | + | ||
| 46 | + | Наконец, для параметра Handled должно быть установлено значение True, чтобы указать, что запрос был успешно обработан (и вернуть в браузер код состояния 200 OK). После добавления этого кода веб-модуль должен выглядеть так: | |
| 47 | + | ||
| 48 | + | ``` pascal | |
| 49 | + | unit mainpage; | |
| 50 | + | ||
| 51 | + | {$mode objfpc}{$H+} | |
| 52 | + | ||
| 53 | + | interface | |
| 54 | + | ||
| 55 | + | uses | |
| 56 | + | Classes, SysUtils, FileUtil, HTTPDefs, websession, fpHTTP, fpWeb; | |
| 57 | + | ||
| 58 | + | type | |
| 59 | + | ||
| 60 | + | { TFPWebModule1 } | |
| 61 | + | ||
| 62 | + | TFPWebModule1 = class(TFPWebModule) | |
| 63 | + | procedure DataModuleRequest(Sender: TObject; ARequest: TRequest; | |
| 64 | + | AResponse: TResponse; var Handled: Boolean); | |
| 65 | + | private | |
| 66 | + | { private declarations } | |
| 67 | + | public | |
| 68 | + | { public declarations } | |
| 69 | + | end; | |
| 70 | + | ||
| 71 | + | var | |
| 72 | + | FPWebModule1: TFPWebModule1; | |
| 73 | + | ||
| 74 | + | implementation | |
| 75 | + | ||
| 76 | + | {$R *.lfm} | |
| 77 | + | ||
| 78 | + | { TFPWebModule1 } | |
| 79 | + | ||
| 80 | + | procedure TFPWebModule1.DataModuleRequest(Sender: TObject; ARequest: TRequest; | |
| 81 | + | AResponse: TResponse; var Handled: Boolean); | |
| 82 | + | begin | |
| 83 | + | AResponse.ContentType := 'text/html;charset=utf-8'; | |
| 84 | + | AResponse.Contents.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'mainpage.html'); | |
| 85 | + | Handled := True; | |
| 86 | + | end; | |
| 87 | + | ||
| 88 | + | begin | |
| 89 | + | RegisterHTTPModule('TFPWebModule1', TFPWebModule1); | |
| 90 | + | end. | |
| 91 | + | ``` | |
| 92 | + | ||
| 93 | + | ### Развертывание приложения CGI | |
| 94 | + | ||
| 95 | + | В этом разделе предполагается, что используется веб-сервер Apache. Конечно, можно использовать и другие веб-серверы, поддерживающие CGI (nginx, cherokee). | |
| 96 | + | ||
| 97 | + | Apache можно загрузить здесь: <http://httpd.apache.org/download.cgi> или установить с помощью диспетчера пакетов вашего дистрибутива. | |
| 98 | + | ||
| 99 | + | При установке Apache по умолчанию все файлы, расположенные в его каталоге cgi-bin, будут обрабатываться как программы CGI, поэтому пользователь не сможет получить доступ к размещенным там простым файлам HTML. Этот каталог можно задать в файле httpd.conf в следующем разделе: | |
| 100 | + | ||
| 101 | + | # | |
| 102 | + | # ScriptAlias: определяет, какие каталоги содержат сценарии сервера. | |
| 103 | + | # ScriptAliases по сути то же, что и Aliases(псевдонимы), за исключением того, что | |
| 104 | + | # документы в целевом каталоге рассматриваются как приложения и | |
| 105 | + | # запускается сервером по запросу, а не как документы, отправленные на | |
| 106 | + | # клиент. К директивам ScriptAlias применяются те же правила для завершающего символа "/", | |
| 107 | + | # что и к Alias. | |
| 108 | + | # | |
| 109 | + | ScriptAlias /cgi-bin/ "C:/Program Files/Apache Software Foundation/Apache2.2/cgi-bin/" | |
| 110 | + | ||
| 111 | + | Если вы поместите исполняемый файл с именем «mywebpage.cgi» в этот каталог, тогда к странице можно будет получить доступ как <http://localhost/cgi-bin/mywebpage.cgi> (или удаленно с соответствующим IP-адресом или доменным именем). | |
| 112 | + | ||
| 113 | + | Fcl-web с Lazarus в Windows создает файлы .exe. Чтобы Apache обслуживал эти файлы, вам необходимо добавить это: | |
| 114 | + | ||
| 115 | + | AddHandler cgi-script .exe | |
| 116 | + | ||
| 117 | + | И чтобы обслуживать ваши исполняемые файлы из другого каталога, вы добавляете это: | |
| 118 | + | ||
| 119 | + | ``` xml | |
| 120 | + | ScriptAlias /bin/ "C:/lazarus_projects/test-fclweb/bin/" | |
| 121 | + | <Directory "C:/lazarus_projects/test-fclweb/bin/"> | |
| 122 | + | AllowOverride None | |
| 123 | + | Options None | |
| 124 | + | Order allow,deny | |
| 125 | + | Allow from all | |
| 126 | + | </Directory> | |
| 127 | + | ``` | |
| 128 | + | ||
| 129 | + | ### Форматирование HTML и читаемых полей запроса | |
| 130 | + | ||
| 131 | + | В предыдущем примере была показана простая HTML-страница. Можно, например, пожелать | |
| 132 | + | ||
| 133 | + | - динамически изменять вывод HTML-страницы и | |
| 134 | + | - при чтении переменных, которые браузер передал веб-странице в полях запроса (например, в действиях HTTP GET и HTTP POST). | |
| 135 | + | ||
| 136 | + | Простое решение для первой проблемы - просто использовать стандартную подпрограмму Паскаля Format с добавлением %s или %d в файл HTML в соответствующие места, которые получат настраиваемое значение. | |
| 137 | + | ||
| 138 | + | ### Чтение данных GET | |
| 139 | + | ||
| 140 | + | Чтобы прочитать переменные GET, можно использовать `ARequest.QueryFields`, который является потомком TStrings. Каждая переменная будет находиться в отдельной строке в TStrings в формате имя_переменной = значение, аналогично тому, как они отображаются в адресе страницы браузера. Для поиска определенной переменной можно использовать `ARequest.QueryFields.Values[]`, передав имя переменной в скобках, чтобы получить обратно ее значение, вместо ручного анализа строки. | |
| 141 | + | ||
| 142 | + | Итоговый код: | |
| 143 | + | ||
| 144 | + | ``` pascal | |
| 145 | + | procedure TFPWebModule1.DataModuleRequest(Sender: TObject; ARequest: TRequest; | |
| 146 | + | AResponse: TResponse; var Handled: Boolean); | |
| 147 | + | var | |
| 148 | + | HexText, AsciiText: string; | |
| 149 | + | begin | |
| 150 | + | HexText := ARequest.QueryFields.Values['hex']; | |
| 151 | + | AsciiText := HexToAnsii(HexText); | |
| 152 | + | ||
| 153 | + | AResponse.ContentType := 'text/html;charset=utf-8'; | |
| 154 | + | AResponse.Contents.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'mainpage.html'); | |
| 155 | + | AResponse.Contents.Text := Format(AResponse.Contents.Text, | |
| 156 | + | [HexText, AsciiText]); | |
| 157 | + | Handled := True; | |
| 158 | + | end; | |
| 159 | + | ``` | |
| 160 | + | ||
| 161 | + | ### Чтение данных POST | |
| 162 | + | ||
| 163 | + | Данные, отправленные запросами POST, можно получить из `TRequest.Content`. Он будет без заголовков запроса - другими словами, он будет содержать тело запроса. | |
| 164 | + | ||
| 165 | + | К отправленным данным формы также можно получить доступ с помощью `TRequest.ContentFields`, который представляет собой содержимое, проанализированное как поля, разделенные знаком `&` и декодированные. Например, следующий набор значений формы: | |
| 166 | + | ||
| 167 | + | `login: dfg 345&&`\ | |
| 168 | + | `login_senha: ====`\ | |
| 169 | + | `email: dfg` | |
| 170 | + | ||
| 171 | + | Будут преобразованы в 'APPLICATION/X-WWW-FORM-URLENCODED' следующим образом (см. [wikipedia POST (HTTP)](http://en.wikipedia.org/wiki/POST_%28HTTP%29)): | |
| 172 | + | ||
| 173 | + | `login=dfg+345%26%26&login_senha=%3D%3D%3D%3D&email=dfg` | |
| 174 | + | ||
| 175 | + | И будет доступно в `TRequest.ContentFields` через индекс строки или через свойство Values, что удобнее: | |
| 176 | + | ||
| 177 | + | `TRequest.ContentFields[0]: login=dfg 345&&`\ | |
| 178 | + | `TRequest.ContentFields[1]: login_senha=====`\ | |
| 179 | + | `TRequest.ContentFields[2]: email=dfg`\ | |
| 180 | + | `TRequest.ContentFields.Values['email']: dfg` | |
| 181 | + | ||
| 182 | + | Если используются другие типы mime, кроме 'MULTIPART/FORM-DATA' и 'APPLICATION/X-WWW-FORM-URLENCODED' (типы, поддерживаемые формами HTML): | |
| 183 | + | ||
| 184 | + | - контент доступен только в `TRequest.Content`, но не в `TRequest.ContentFields` | |
| 185 | + | - использование этих mime-типов вызывает исключение для FPC 2.4.2 (исправлено в FPC 2.5+). | |
| 186 | + | ||
| 187 | + | Обратите внимание, что HTTP POST также может отправлять поля запроса (в URL-адресе), например <http://server/bla?question=how>, и к ним обращается `TRequest.QueryFields`, как описано в предыдущем разделе. | |
| 188 | + | ||
| 189 | + | ``` pascal | |
| 190 | + | procedure TFPWebModule1.DataModuleRequest(Sender: TObject; ARequest: TRequest; | |
| 191 | + | AResponse: TResponse; var Handled: Boolean); | |
| 192 | + | var | |
| 193 | + | lData: String; | |
| 194 | + | begin | |
| 195 | + | lData := ARequest.Content; | |
| 196 | + | ``` | |
| 197 | + | ||
| 198 | + | ### Чтение двоичных данных POST | |
| 199 | + | ||
| 200 | + | Загруженные файлы сохраняются во временном расположении с временным именем файла, чтобы сохранить файл, вы должны переместить его в постоянное расположение. | |
| 201 | + | ||
| 202 | + | Для получения данных на сервере, который был размещен, например, как multipart/form-data используйте что-то вроде этого: | |
| 203 | + | ||
| 204 | + | ``` pascal | |
| 205 | + | procedure TMainWebModule.TFPWebActions2Request(Sender: TObject; | |
| 206 | + | ARequest: TRequest; AResponse: TResponse; var Handled: Boolean); | |
| 207 | + | var | |
| 208 | + | i: Integer; | |
| 209 | + | begin | |
| 210 | + | // Обработать все полученные файлы | |
| 211 | + | for i := 0 to ARequest.Files.Count - 1 do | |
| 212 | + | begin | |
| 213 | + | // Настоятельно рекомендуется делать что-то еще, кроме Writeln ;) | |
| 214 | + | writeln ('Полученное имя файла: '+ARequest.Files[i].LocalFileName); | |
| 215 | + | end; | |
| 216 | + | ||
| 217 | + | Handled := true; | |
| 218 | + | end; | |
| 219 | + | ``` | |
| 220 | + | ||
| 221 | + | Клиент может отправлять данные, например, FileFormPost. | |
| 222 | + | ||
| 223 | + | ## Специализированные модули | |
| 224 | + | ||
| 225 | + | Класс *TFPWebModule* (используемый ниже) - это простой пример WEb-модуля, который можно использовать для всех видов HTTP-запросов. | |
| 226 | + | ||
| 227 | + | Однако fpweb поставляется с некоторыми специализированными модулями, которые имеют дополнительную поддержку для специализированных задач: | |
| 228 | + | ||
| 229 | + | - Класс **TSimpleFileModule** в модуле *fpwebfile.pp* можно использовать для отправки файлов. Вы указываете ему каталог, и он делает все остальное. | |
| 230 | + | - Класс **TFPHTMLModule** в модуле *fphtml.pp* можно использовать для создания HTML. | |
| 231 | + | - Класс **TProxyWebModule** в модуле *fpwebproxy.pp* - это готовый прокси для пересылки. | |
| 232 | + | - Класс **TFPWebProviderDataModule** в модуле *fpwebdata.pp* обслуживает данные в формате JSON, которые могут использоваться хранилищами ExtJS. | |
| 233 | + | - Класс **TSQLDBRestModule** в модуле *sqldbrestmodule.pp* реализует полноценный сервер REST, поддерживаемый SQLDB. См. Дополнительную информацию в [[SQLDBRestBridge]]. | |
| 234 | + | - Класс **TJSONRPCModule** в модуле *webjsonrpc.pp* реализует службу JSON-RPC. | |
| 235 | + | - Класс **TExtDirectModule** в модуле *fpextdirect.pp* реализует вариант Ext.Direct службы JSON-RPC. | |
| 236 | + | ||
| 237 | + | ## Использование нескольких модулей | |
| 238 | + | ||
| 239 | + | Если в веб-приложении только один модуль, все запросы будут направлены в этот модуль. | |
| 240 | + | ||
| 241 | + | По мере роста вашего веб-приложения можно использовать несколько модулей. Новый модуль можно добавить, выбрав 'File - New', а затем один из 'Web module' или 'HTML Web Module'. | |
| 242 | + | ||
| 243 | + | FCL-web использует URL-адрес, чтобы определить, как следует обрабатывать HTTP-запрос. Поэтому он должен знать, какие веб-модули существуют в приложении. Для этого каждый модуль должен быть зарегистрирован. | |
| 244 | + | ||
| 245 | + | Каждый модуль регистрируется в fcl-web в разделе инициализации модуля, в котором он определен: | |
| 246 | + | ||
| 247 | + | ``` pascal | |
| 248 | + | RegisterHTTPModule('location', TMyModule); | |
| 249 | + | ``` | |
| 250 | + | ||
| 251 | + | Затем модуль будет вызван, если используется URL-адрес формы | |
| 252 | + | ||
| 253 | + | `http://www.mysite.org/mycgi.cgi/location` | |
| 254 | + | ||
| 255 | + | или | |
| 256 | + | ||
| 257 | + | `http://www.mysite.org/mycgi.cgi?module=location` | |
| 258 | + | ||
| 259 | + | Если присутствует несколько модулей, имя модуля должно появиться в URL-адресе, в противном случае возникнет ошибка. | |
| 260 | + | ||
| 261 | + | Это поведение также можно принудительно настроить для приложений, которые имеют только один модуль, установив для свойства приложения AllowDefaultModule значение false: | |
| 262 | + | ||
| 263 | + | ``` pascal | |
| 264 | + | Application.AllowDefaultModule := False; | |
| 265 | + | ``` | |
| 266 | + | ||
| 267 | + | В этом случае приложение fcl-web всегда будет требовать имя модуля в URL-адресе. | |
| 268 | + | ||
| 269 | + | Имя переменной запроса, определяющей имя модуля (по умолчанию это 'module'), можно задать в свойстве `Application.ModuleVariable`. Следующий код | |
| 270 | + | ||
| 271 | + | ``` pascal | |
| 272 | + | Application.ModuleVariable := 'm'; | |
| 273 | + | ``` | |
| 274 | + | ||
| 275 | + | гарантирует, что следующий URL-адрес будет направлен в TMyModule: | |
| 276 | + | ||
| 277 | + | `http://www.mysite.org/mycgi.cgi?m=location` | |
| 278 | + | ||
| 279 | + | Если всего этого недостаточно для определения модуля, которому следует передать запрос, можно использовать событие `Application.OnGetModule`. Это тип `TGetModuleEvent`: | |
| 280 | + | ||
| 281 | + | ``` pascal | |
| 282 | + | type | |
| 283 | + | TGetModuleEvent = Procedure (Sender : TObject; ARequest : TRequest; | |
| 284 | + | Var ModuleClass : TCustomHTTPModuleClass) of object; | |
| 285 | + | ``` | |
| 286 | + | ||
| 287 | + | Создание обработчика событий для этого события позволяет точно контролировать модуль, созданный для обработки запроса: запрос (переданный в ARequest) может быть исследован, а для переменной 'ModuleClass' должен быть задан класс модуля, который должен обрабатывать Запрос. | |
| 288 | + | ||
| 289 | + | Если 'ModuleClass' при возврате равен 'Nil', в браузер будет отправлено сообщение об ошибке. | |
| 290 | + | ||
| 291 | + | ## Использование Actions | |
| 292 | + | ||
| 293 | + | Модуль можно использовать для группировки определенных видов действий, которые логически связаны друг с другом. Представьте себе модуль TUserModule, который используется для управления пользователями на веб-страницах. С пользователем может быть связано несколько действий: | |
| 294 | + | ||
| 295 | + | - Создание | |
| 296 | + | - Удаление | |
| 297 | + | - Редактирование | |
| 298 | + | - Отображение | |
| 299 | + | ||
| 300 | + | Эти разные действия могут обрабатываться одним и тем же модулем. Можно определить действие по URL-адресу вручную, например: | |
| 301 | + | ||
| 302 | + | `http://mysite/mycgi.cgi/user?action=delete&id=12` | |
| 303 | + | ||
| 304 | + | Это можно автоматизировать. | |
| 305 | + | ||
| 306 | + | Для упрощения разделения различных действий в модуле есть свойство actions: это коллекция, в которой каждый элемент связан с различным ответом на запрос. Действия имеют различные свойства: | |
| 307 | + | ||
| 308 | + | Name | |
| 309 | + | Название действия. URL-адрес будет проверен, чтобы определить название действия. | |
| 310 | + | ||
| 311 | + | Content | |
| 312 | + | строка. Если задано, оно отправляется в браузер. | |
| 313 | + | ||
| 314 | + | Contents | |
| 315 | + | список строк. Если задано, оно отправляется в браузер. | |
| 316 | + | ||
| 317 | + | ContentProducer | |
| 318 | + | если задано, ContentProducer будет обрабатывать запрос. | |
| 319 | + | ||
| 320 | + | Default | |
| 321 | + | если установлено значение «True», это действие является действием по умолчанию. Это означает, что если FCL-Web не может определить имя действия, будет выполнено это действие. | |
| 322 | + | ||
| 323 | + | Template | |
| 324 | + | если установлено, этот шаблон будет обработан, а результаты отправлены в браузер. | |
| 325 | + | ||
| 326 | + | Также есть некоторые события: | |
| 327 | + | ||
| 328 | + | BeforeRequest | |
| 329 | + | выполняется до обработки запроса. Может использоваться для установки 'Content' или других свойств. | |
| 330 | + | ||
| 331 | + | AfterRequest | |
| 332 | + | выполняется после обработки запроса. | |
| 333 | + | ||
| 334 | + | OnRequest | |
| 335 | + | обработчик событий для обработки запроса. Если задано, обработчик используется для обработки запроса. | |
| 336 | + | ||
| 337 | + | Опять же, как и в случае нескольких модулей, URL-адрес используется для определения того, какое действие выполнить. Используется часть сразу после части модуля (в данном примере "user"): | |
| 338 | + | ||
| 339 | + | `http://mysite/mycgi.cgi/user/delete&id=12` | |
| 340 | + | ||
| 341 | + | выполнит действие под названием 'delete'. | |
| 342 | + | ||
| 343 | + | Свойство 'ActionVar' модуля можно использовать для установки имени используемой переменной запроса. Настройка | |
| 344 | + | ||
| 345 | + | ``` pascal | |
| 346 | + | UserModule.ActionVar := 'a'; | |
| 347 | + | ``` | |
| 348 | + | ||
| 349 | + | может использоваться для изменения указанного выше URL на | |
| 350 | + | ||
| 351 | + | `http://mysite/mycgi.cgi/user?a=delete&id=12` | |
| 352 | + | ||
| 353 | + | Если в приложении только один модуль, URL-адрес можно сократить до | |
| 354 | + | ||
| 355 | + | `http://mysite/mycgi.cgi/delete&id=12` | |
| 356 | + | ||
| 357 | + | ## Использование HTML-шаблонов | |
| 358 | + | ||
| 359 | + | Информацию об использовании шаблонов, тегов шаблонов и параметров тегов шаблонов для создания страниц ответов см. в файле fptemplate.txt в каталоге FPC в /packages/fcl-base/texts/. | |
| 360 | + | ||
| 361 | + | Примеры проектов, демонстрирующих использование шаблонов, можно найти в каталоге FPC в /packages/fcl-web/examples/fptemplate/ (дополнительные сведения см. в README.txt). (В более ранних версиях эти примеры находились в каталоге Lazarus в /components/fpweb/demo/fptemplate/) | |
| 362 | + | ||
| 363 | + | ## Советы и устранение неполадок | |
| 364 | + | ||
| 365 | + | ### Отправка кодов результатов | |
| 366 | + | ||
| 367 | + | Чтобы отправить HTTP-ответ, отличный от 200 OK, используйте **AResponse.Code** и **AResponse.CodeText**, например | |
| 368 | + | ||
| 369 | + | ``` pascal | |
| 370 | + | AResponse.Code := 404; | |
| 371 | + | AResponse.CodeText := 'Document not found'; | |
| 372 | + | ``` | |
| 373 | + | ||
| 374 | + | ### Отправка двоичных данных | |
| 375 | + | ||
| 376 | + | Подход, который, кажется, работает для отправки, например, файл tiff с веб-сервера на клиент - адаптированный из \$(fpcdirectory)\packages\fcl-web\examples\jsonrpc\demo1\wmdemo.pp - что-то вроде: | |
| 377 | + | ||
| 378 | + | ``` pascal | |
| 379 | + | AResponse.ContentStream := TMemoryStream.Create; | |
| 380 | + | ||
| 381 | + | try | |
| 382 | + | AResponse.ContentStream.LoadFromFile('/tmp/sample.tiff'); | |
| 383 | + | AResponse.ContentType := 'image/tiff'; //или любой другой тип MIME, который вы хотите отправить | |
| 384 | + | //что делать: есть пример fpweb, который получает тип mime из расширения файла ... | |
| 385 | + | AResponse.ContentLength:=AResponse.ContentStream.Size; //видимо не происходит автоматически? | |
| 386 | + | AResponse.SendContent; | |
| 387 | + | finally | |
| 388 | + | AResponse.ContentStream.Free; | |
| 389 | + | end; | |
| 390 | + | ||
| 391 | + | Handled := true; | |
| 392 | + | ``` | |
| 393 | + | ||
| 394 | + | ### Error: Could not determine HTTP module for request | |
| 395 | + | ||
| 396 | + | У вас может быть несколько модулей и несколько actions. Если вы укажете URL-адрес только с 1 элементом, например: | |
| 397 | + | ||
| 398 | + | ```html4strict | |
| 399 | + | http://localhost/cgi-bin/somemodule | |
| 400 | + | ``` | |
| 401 | + | ||
| 402 | + | тогда fpweb предполагает, что вы указываете действие. Если у вас не установлен модуль по умолчанию, вы получите внутреннюю ошибку сервера 500 (не удалось определить модуль HTTP для запроса) | |
| 403 | + | ||
| 404 | + | Вы можете изменить это поведение, чтобы вместо этого fpweb отображал имя модуля, установив для свойства приложения `PreferModuleName` значение `true`. | |
| 405 | + | ||
| 406 | + | ### Error: response code 500 Internal Server error when trying to handle DELETE method | |
| 407 | + | ||
| 408 | + | В FPC 2.6.2 и ниже fcl-web не принимает метод DELETE и выдает ошибку. | |
| 409 | + | ||
| 410 | + | ### fpWeb/FCGI и Apache 2.4 (режим mod_proxy_fcgi) | |
| 411 | + | ||
| 412 | + | 1, Enable following modules: setenvif_module, proxy_module and proxy_fcgi_module\ | |
| 413 | + | (on CentOS 7 modules are defined in file /etc/httpd/conf.modules.d/00-base.conf and /etc/httpd/conf.modules.d/00-proxy.conf). Если вы хотите развернуть приложение FCGI позади прокси-сервера Apache 2.4+, вам понадобится переменная PATH_INFO в заголовках, которые отправляются через сокет демону FCGI. | |
| 414 | + | ||
| 415 | + | 1\. Включите следующие модули: setenvif_module, proxy_module и proxy_fcgi_module\ | |
| 416 | + | (в CentOS 7 модули определены в файлах /etc/httpd/conf.modules.d/00-base.conf и /etc/httpd/conf.modules.d/00-proxy.conf). | |
| 417 | + | ||
| 418 | + | LoadModule setenvif_module modules/mod_setenvif.so | |
| 419 | + | LoadModule proxy_module modules/mod_proxy.so | |
| 420 | + | LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so | |
| 421 | + | ||
| 422 | + | 2\. Конфигурация обратного прокси для fpWeb/FCGI, прослушивающего порт 9000.\ | |
| 423 | + | \$1 = module name\ | |
| 424 | + | \$2 = action name | |
| 425 | + | ||
| 426 | + | SetEnvIf Request_URI . proxy-fcgi-pathinfo=full | |
| 427 | + | ProxyPassMatch "/fcgi/(.*)/(.*)" "fcgi://127.0.0.1:9000/$1/$2" | |
| 428 | + | ||
| 429 | + | ### fpWeb/FCGI и nginx | |
| 430 | + | ||
| 431 | + | Для правильной маршрутизации fcl-web требует переменную PATH_INFO в заголовках, отправленных из nginx. Для этого вы должны разделить весь URL-адрес на имя приложения FastCGI и часть информации о пути с помощью оператора конфигурации *fastcgi_split_path_info*. Оператор принимает регулярное выражение и помещает второе совпадение в конфигурационную переменную *\$fastcgi_path_info*. Эту переменную можно передать вашему приложению с помощью оператора *fastcgi_param*. | |
| 432 | + | ||
| 433 | + | Следующий пример конфигурации включает в себя полноценный виртуальный хост для nginx, который передает все из *<http://myserver:8080/mycgiapp/>* во внешнее приложение FastCGI. | |
| 434 | + | ||
| 435 | + | server { | |
| 436 | + | ||
| 437 | + | listen 8080; | |
| 438 | + | listen [::]:8080; | |
| 439 | + | ||
| 440 | + | server_name _; | |
| 441 | + | ||
| 442 | + | root "/var/www"; | |
| 443 | + | ||
| 444 | + | location /mycgiap/ { | |
| 445 | + | # setting up PATH_INFO | |
| 446 | + | fastcgi_split_path_info ^(/mycgiapp/)(.*)$; | |
| 447 | + | fastcgi_param PATH_INFO $fastcgi_path_info; | |
| 448 | + | ||
| 449 | + | # other parameters | |
| 450 | + | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | |
| 451 | + | fastcgi_param QUERY_STRING $query_string; | |
| 452 | + | fastcgi_param REQUEST_METHOD $request_method; | |
| 453 | + | fastcgi_param CONTENT_TYPE $content_type; | |
| 454 | + | fastcgi_param CONTENT_LENGTH $content_length; | |
| 455 | + | fastcgi_param SCRIPT_NAME $fastcgi_script_name; | |
| 456 | + | fastcgi_param REQUEST_URI $request_uri; | |
| 457 | + | fastcgi_param DOCUMENT_URI $document_uri; | |
| 458 | + | fastcgi_param DOCUMENT_ROOT $document_root; | |
| 459 | + | fastcgi_param SERVER_PROTOCOL $server_protocol; | |
| 460 | + | fastcgi_param REQUEST_SCHEME $scheme; | |
| 461 | + | fastcgi_param HTTPS $https if_not_empty; | |
| 462 | + | fastcgi_param GATEWAY_INTERFACE CGI/1.1; | |
| 463 | + | fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; | |
| 464 | + | fastcgi_param REMOTE_ADDR $remote_addr; | |
| 465 | + | fastcgi_param REMOTE_PORT $remote_port; | |
| 466 | + | fastcgi_param SERVER_ADDR $server_addr; | |
| 467 | + | fastcgi_param SERVER_PORT $server_port; | |
| 468 | + | fastcgi_param SERVER_NAME $server_name; | |
| 469 | + | ||
| 470 | + | # pass requests to your FastCGI application | |
| 471 | + | fastcgi_pass 127.0.0.1:9000; | |
| 472 | + | } | |
| 473 | + | } | |
| 474 | + | ||
| 475 | + | ## Примечание | |
| 476 | + | ||
| 477 | + | - Модуль cgiapp устарел, по возможности используйте fpcgi. | |
| 478 | + | ||
| 479 | + | - Модули fastcgi, custfcgi и fpfcgi не поддерживаются в Darwin в настоящее время, потому что он использует другой механизм, чем опция MSG_NOSIGNAL для recv(), чтобы указать, что SIGPIPE не должен генерироваться в случае разрыва соединения. См. <http://lists.apple.com/archives/macnetworkprog/2002/Dec/msg00091.html>, чтобы узнать, как это исправить. | |
| 480 | + | ||
| 481 | + | - Если вы развертываете свое приложение CGI и получаете такие ошибки, как "Error: No action name and no default action", вы должны убедиться, что для URL-адреса назначено действие, или перехватить неподдерживаемые действия с действием, отмеченным по умолчанию. В обоих случаях следует использовать обработчик события `OnRequest` для действия, которое устанавливает `Handled:=true`. | |
| 482 | + | ||
| 483 | + | ## См. также | |
| 484 | + | ||
| 485 | + | - [[fpWeb Tutorial]] | |
| 486 | + | - [[fphttpclient]] - Часть fcl-web, которую можно использовать отдельно в клиентских приложениях | |
| 487 | + | - *write me!* fphttpserver - Небольшой автономный веб-сервер Object Pascal. Может использоваться для обслуживания приложений fcl-web CGI. | |
| 488 | + | - [[CGI Web Programming|CGI_Web_Programming#Debugging_CGI]] Информация об отладке приложений CGI | |
| 489 | + | - [Часть учебника Leonardo Ramé](https://github.com/leonardorame/Ext4-MVC-Tutorial/wiki/Lazarus-Server), в котором показано, как писать приложение fcl-web CGI; включает пример создания содержимого JSON | |
| 490 | + | ||
| 491 | + | --- | |
| 492 | + | *From the Free Pascal wiki, page "fcl-web/ru", as it stood on 2021-01-07 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
