Erlang read post request

江枫思渺然 提交于 2019-12-08 03:40:36

问题


I'm trying to build a simple web server based on Erlang, so far I'm able to start a server with below code. tutorial ref

-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>" ]).

I'm trying to get the response but getting the permission error.

You don't have permission to access /erl/hello_world:servie on this server.

I'm aiming to build Erlang based server which can read post request and store the post data in MYSQL.

If anyone can help me with instructions or with some code to start the Erlang server for reading POST request that will be so helpful.

Thanks


回答1:


I'm aiming to build Erlang based server which can read post request and store the post data in MYSQL.

I used rebar3 to create an app:

$ rebar3 new app myserver

Then I specified mysql-otp as a dependency so that I could use mysql. I basically ignored the OTP app, and I added some source code to start an inets server. See here.

Here's the module I used to start the inets httpd server, handle the request, and insert the post data into a mysql db:

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]
        ).

I put that code in the src directory of my app, which was named myserver. Here is my directory structure:

~/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

Here is the server.conf file:

[
  {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"}
].

Then, to run the app I did:

~/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>

I looked at that output to get the server's port: 55804, which I used to send a post request with 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
~$ 

Then I stopped the inets httpd server:

4> my:stop(S).
ok

5> 

Then I checked the mysql db for a new entry:

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

Success!

Here's my rebar.config file:

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



回答2:


you're calling inets:start/0 and inets:start/2, in the example it's just one or the other, don't know if that'd make a difference.



来源:https://stackoverflow.com/questions/50167747/erlang-read-post-request

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!