Erlang чтение почтового запроса

Я пытаюсь создать простой веб-сервер на основе Erlang, пока я могу запустить сервер с кодом ниже. ссылка на учебник

-module(helloworld).
-export([
  main/1,
  run_server/0,
  start/0,
  service/3,
]).

main(_) ->
  start(),
  receive
    stop -> ok
  end.

run_server() ->
  ok = inets:start(),
  {ok, _} = inets:start(httpd, [

    {modules, [ 
         mod_alias, 
         mod_auth, 
         mod_esi, 
         mod_actions, 
         mod_cgi, 
         mod_dir,
         mod_get, 
         mod_head, 
         mod_log, 
         mod_disk_log 
      ]}, 
    {port, 8000},
    {server_name,"helloworld"}, 
      {server_root,"/tmp"}, 
      {document_root,"."}, 
      {erl_script_alias, {"/erl", [helloworld]}}, 
      {error_log, "error.log"}, 
      {security_log, "security.log"}, 
      {transfer_log, "transfer.log"}, 

      {mime_types,[ 
         {"html","text/html"}, {"css","text/css"}, {"js","application/x-javascript"} ]} 
   ]). 

start() -> run_server().

service(SessionID, _Env, _Input) -> mod_esi:deliver(SessionID, [ 
   "Content-Type: text/html\r\n\r\n", "<html><body>Hello, World!</body></html>" ]).

Я пытаюсь получить ответ, но получаю ошибку разрешения.

У вас нет разрешения на доступ к /erl/hello_world:servie на этом сервере.

Я стремлюсь создать сервер на основе Erlang, который может читать почтовый запрос и хранить данные сообщения в MYSQL.

Если кто-нибудь может помочь мне с инструкциями или с некоторым кодом, чтобы запустить сервер Erlang для чтения POST-запроса, это будет очень полезно.

Спасибо


person piyush singh    schedule 04.05.2018    source источник
comment
Я только что проработал весь inets материал. Вот несколько моих постов с ответами: cgi/json: stackoverflow.com/questions/49171591/, esi: stackoverflow.com/questions/49024122/   -  person 7stud    schedule 06.05.2018


Ответы (3)


Я стремлюсь создать сервер на основе Erlang, который может читать почтовый запрос и хранить данные сообщения в MYSQL.

Я использовал rebar3 для создания приложения:

$ rebar3 new app myserver

Затем я указал mysql-otp в качестве зависимости, чтобы можно было использовать mysql. Я в основном проигнорировал приложение OTP и добавил исходный код для запуска сервера inets. См. здесь.

Вот модуль, который я использовал для запуска сервера inets httpd, обработки запроса и вставки данных сообщения в базу данных mysql:

my.erl:

-module(my).
-compile(export_all).

ensure_inets_start() ->
    case inets:start() of
        ok -> ok;
        {error,{already_started,inets}} -> ok
    end.

start() ->
    ok = my:ensure_inets_start(),

    %Construct path to myserver/priv/server.conf:
    PrivDir = code:priv_dir(myserver),
    ServerConfPath = filename:join(PrivDir, "server.conf"),

    {ok, Server} = inets:start(httpd, 
        [{proplist_file, ServerConfPath}]
    ),
    Server.


stop(Server) ->
    ok = inets:stop(httpd, Server).

log(Data) ->
    {ok, IoDevice} = file:open(
        %"/Users/7stud/erlang_programs/inets_post_request/myserver/logs/mylog.log",
        "./logs/mylog.log",
        [append]
    ),

    file:write(IoDevice, Data),
    file:close(IoDevice).

handle_request(SessionID, Env, Input) ->
    Headers = "Content-Type: text/html\r\n\r\n",
    Data = [
        <<"Hello, ">>, 
        "esi!\n"
    ],

    log(io_lib:format(
        "Inside my:handle_request()\nSessionId=~p\nEnv=~p\nInput=~p\n", 
        [SessionID, Env, Input]
    )),

    PostData = list_to_binary(Input),
    [NamePair, InfoPair] = binary:split(PostData, <<"&">>),
    [<<"name">>, Name] = binary:split(NamePair, <<"=">>),
    [<<"info">>, Info] = binary:split(InfoPair, <<"=">>),
    do_mysql(Name, Info),

    mod_esi:deliver(SessionID, Headers),  %Headers must be a string.
    mod_esi:deliver(SessionID, Data).     %Data can be an iolist.

do_mysql(Name, Info) ->
    {ok, MysqlPid} = mysql:start_link(
                  [{host, "localhost"}, 
                   {user, "root"},
                   {password, ""}, 
                   {database, "mydb"}
                  ]
                ),

    %{ok, ColumnNames, Rows} = mysql:query(
    %            Pid, 
    %            <<"SELECT * FROM people">>),
    %io:format("ColumnNames: ~p~nRows: ~p~n", [ColumnNames, Rows]).

    ok = mysql:query(
           MysqlPid, 
           "INSERT INTO people (name, info) VALUES (?, ?)", [Name, Info]
        ).

Я поместил этот код в каталог src моего приложения, которое было названо myserver. Вот моя структура каталогов:

~/erlang_programs/inets_post_request$ tree myserver

myserver
├── htdocs
├── logs
│   ├── errors.log
│   ├── mylog.log
│   └── requests.log
├── priv
│   └── server.conf
├── rebar.config  (created by rebar3)
├── rebar.lock    (created by rebar3)
└── src
    ├── my.erl
    ├── myserver.app.src  (created by rebar3)
    ├── myserver_app.erl  (created by rebar3)
    └── myserver_sup.erl  (created by rebar3)

(compiling with rebar3 creates all this stuff:)

├── _build
│   └── default
│       └── lib
│           ├── myserver
│           │   ├── ebin
│           │   │   ├── my.beam
│           │   │   ├── myserver.app
│           │   │   ├── myserver_app.beam
│           │   │   └── myserver_sup.beam
│           │   ├── include -> ../../../../include
│           │   ├── priv -> ../../../../priv
│           │   └── src -> ../../../../src
│           └── mysql
│               ├── CHANGELOG.md
│               ├── COPYING
│               ├── COPYING.LESSER
│               ├── Makefile
│               ├── README.md
│               ├── changelog.sh
│               ├── doc
│               │   └── overview.edoc
│               ├── ebin
│               │   ├── mysql.app
│               │   ├── mysql.beam
│               │   ├── mysql_cache.beam
│               │   ├── mysql_encode.beam
│               │   ├── mysql_protocol.beam
│               │   ├── mysql_sock_ssl.beam
│               │   └── mysql_sock_tcp.beam
│               ├── erlang-mk.build.config
│               ├── erlang.mk
│               ├── include
│               │   ├── protocol.hrl
│               │   ├── records.hrl
│               │   └── server_status.hrl
│               ├── priv
│               │   └── edoc-style.css
│               ├── src
│               │   ├── mysql.app.src
│               │   ├── mysql.erl
│               │   ├── mysql_cache.erl
│               │   ├── mysql_encode.erl
│               │   ├── mysql_protocol.erl
│               │   ├── mysql_sock_ssl.erl
│               │   └── mysql_sock_tcp.erl
│               └── test
│                   ├── error_logger_acc.erl
│                   ├── mock_tcp.erl
│                   ├── mysql_encode_tests.erl
│                   ├── mysql_protocol_tests.erl
│                   ├── mysql_tests.erl
│                   ├── ssl
│                   │   ├── Makefile
│                   │   └── my-ssl.cnf.template
│                   ├── ssl_tests.erl
│                   └── transaction_tests.erl

Вот файл server.conf:

[
  {modules, [
    mod_alias,
    mod_actions,
    mod_esi,
    mod_cgi,
    mod_get,
    mod_log
  ]},
  {bind_address, "localhost"}, 
  {port,0},
  {server_name,"httpd_test"},
  {server_root,"./"},
  {document_root,"./htdocs"},
  {erl_script_alias, {"/erl", [my]} },
  {erl_script_nocache, true},
  {error_log, "./logs/errors.log"},
  {transfer_log, "./logs/requests.log"}
].

Затем, чтобы запустить приложение, которое я сделал:

~/erlang_programs/inets_post_request/myserver$ rebar3 compile (may not be necessary)
...
...
~/erlang_programs/inets_post_request/myserver$ rebar3 shell (looks like this also will fetch the dependencies, then compile)
===> Verifying dependencies...
===> Compiling myserver
/Users/7stud/erlang_programs/inets_post_request/myserver/_build/default/lib/myserver/src/my.erl:2: Warning: export_all flag enabled - all functions will be exported

Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V9.2  (abort with ^G)
1> S = my:start().
<0.127.0>

2> httpd:info(S). 
[{mime_types,[{"htm","text/html"},{"html","text/html"}]},
 {server_name,"httpd_test"},
 {erl_script_nocache,true},
 {bind_address,{127,0,0,1}},
 {modules,[mod_alias,mod_actions,mod_esi,mod_cgi,mod_get,
           mod_log]},
 {server_root,"/Users/7stud/erlang_programs/inets_post_request/myserver/src"},
 {erl_script_alias,{"/erl",[my]}},
 {port,55804},
 {transfer_log,<0.134.0>},
 {error_log,<0.133.0>},
 {document_root,"./htdocs"}]

3>

Я просмотрел этот вывод, чтобы получить порт сервера: 55804, который я использовал для отправки почтового запроса с помощью curl:

~$ curl -v --data "name=Kathy&info=xyz" "http://localhost:55804/erl/my:handle_request"
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 55804 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 55804 (#0)
> POST /erl/my:handle_request HTTP/1.1
> Host: localhost:55804
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 19
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 19 out of 19 bytes
< HTTP/1.1 200 OK
< Date: Wed, 09 May 2018 00:10:42 GMT
< Server: inets/6.4.5
< Cache-Control: no-cache
< Pragma: no-cache
< Expires: Wed, 09 May 2018 00:10:42 GMT
< Transfer-Encoding: chunked
< Content-Type: text/html
< 
Hello, esi!
* Connection #0 to host localhost left intact
~$ 

Затем я остановил сервер inets httpd:

4> my:stop(S).
ok

5> 

Затем я проверил базу данных mysql на наличие новой записи:

mysql> select * from people;
+----+-------+------+
| id | name  | info |
+----+-------+------+
|  1 | Fred  | abc  |
|  2 | Alice | xxx  |
|  3 | Kathy | xyz  |
+----+-------+------+
4 rows in set (0.00 sec)

Успех!

Вот мой файл rebar.config:

{erl_opts, [debug_info]}.
{deps, [
  {mysql, {git, "https://github.com/mysql-otp/mysql-otp",
          {tag, "1.3.2"}}}
]}.
person 7stud    schedule 09.05.2018

вы вызываете inets:start/0 и inets:start/2, в примере это просто одно или другое, не знаю, будет ли это иметь значение.

person Roman Rabinovich    schedule 05.05.2018

У меня была такая же проблема с тем же плохо написанным учебником. В конце они говорят вам идти к:

http://localhost:8081/erl/hello_world:service

Однако URL-адрес должен быть:

http://localhost:8081/erl/helloworld:service

(Обратите внимание на удаление подчеркивания.)

person Caleb M.    schedule 17.06.2021