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