[6] Nginx Server Setup - Implementing Upload/Download + Simple Upload Client

With directory listing set up, let's implement file upload/download functionality using Drogon.


1. Server Function Implementation

1-1. Implementing Drogon Controller

Register the Drogon Controller. (This step is required for it to be recognized during the build.)

``` cd /root/drogon2/drogon/build/drogon_ctl drogon_ctl create controller FileController ```


1-2. Implement Upload/Download Functionality

Source path: `/root/drogon2/drogon/build/drogon_ctl/testAPI/controllers`

FileController.h

 #pragma once #include 

using namespace drogon;

class FileController : public HttpController { public: std::string _storagePath = "/root/storage/"; METHOD_LIST_BEGIN // Handles POST requests for "/upload" ADD_METHOD_TO(FileController::handleUpload, "/upload", Post);

// Handles GET requests for "/download/{filename}" ADD_METHOD_TO(FileController::handleDownload, "/download/{1}", Get); METHOD_LIST_END

// Method declarations void handleUpload(const HttpRequestPtr& req, std::function&& callback); void handleDownload(const HttpRequestPtr& req, std::function&& callback, const std::string& filename); };


FileController.cc

 #include "FileController.h" #include  #include 

// Upload handler void FileController::handleUpload(const HttpRequestPtr& req, std::function&& callback) { Json::Value respStr; HttpStatusCode code = k200OK;

MultiPartParser fileUpload; do { if (fileUpload.parse(req) != 0) { code = k400BadRequest; respStr = Json::Value("Multipart Format Invalid"); break; }

auto &file = fileUpload.getFiles()[0]; LOG_INFO << "file:" << file.getFileName() << " (extension=" << file.getFileExtension() << ", type=" << file.getFileType() << ", len=" << file.fileLength() << ", md5=" << file.getMd5() << ")";

std::string uploadPath = _storagePath + file.getFileName(); LOG_INFO << "uploadPath:" << uploadPath.c_str();

if (file.saveAs(uploadPath) != 0) { code = k500InternalServerError; respStr = Json::Value("Internal Server Error"); break; } } while(false);

auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(code); callback(resp); }

// Download handler void FileController::handleDownload(const HttpRequestPtr& req, std::function&& callback, const std::string& filename) { std::string filePath = _storagePath + filename; if (std::ifstream(filePath).good()) { auto resp = HttpResponse::newFileResponse(filePath.c_str(), filename.c_str()); resp->setContentTypeCode(CT_APPLICATION_OCTET_STREAM); resp->addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); callback(resp); } else { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k404NotFound); callback(resp); } }

After the above steps, navigate to the build directory and run `make`:

``` cd /root/drogon2/drogon/build/drogon_ctl/testAPI/build make ```


1-3. Modify Drogon Configuration

Edit `/root/drogon2/drogon/build/drogon_ctl/testAPI/config.json` and modify the `client_max_body_size` value (default is 1M).

``` "client_max_body_size": "256M" # Default is 1M, adjust as needed ```

If this value is not modified, a "413 Request Entity Too Large" error will be returned. With these modifications, the server setup is complete.


2. Client Function Implementation

Add an HTML file at the following path: `/root/nginx/html/upload.html`

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>File Upload</title> </head> <body> <h2>Upload a File</h2> <form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="file" required> <br><br> <button type="submit">Send</button> </form> </body> </html> 


3. NGINX Configuration

- Adjust the API alias settings - Also modify `client_max_body_size`

``` user nobody; worker_processes 10;

events { worker_connections 1024; use epoll; }

http { include mime.types; default_type application/octet-stream;

sendfile on; client_max_body_size 256m;

proxy_buffer_size 128k; proxy_buffers 4 256k;

server { listen 10099; server_name localhost;

location /doUpload { alias /root/nginx/html/; index upload.html; autoindex on; }

location /list { alias /root/storage/; autoindex on; # Enable directory listing autoindex_exact_size off; # Display file size in simplified format (optional) autoindex_localtime on; # Display file time in local time (optional) }

location /upload { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8848; # Proxy target server }

location ~ ^/download/(.*) { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:8848/download/$1; # Pass captured variable to backend } } } ```

If a "413 Request Entity Too Large" error occurs, adjust `client_max_body_size`.


4. Verifying Operation

4-1. Verify Upload Operation

- Call the upload API and select a file using the client.

drogon upload


- The server should respond with 200 OK.

200 ok


- Files are saved in the following path: ``` [root@vbox storage] $ ll Total 72 -rw-r--r--. 1 root root 66662 Nov 4 08:48 7.PNG -rw-r--r--. 1 nobody nobody 2 Nov 4 06:21 test.txt ```

You can also confirm this in the listing set up in “[5] NGINX Server Setup.”

drogon download


4-2. Verify Download Operation

- In a web browser, go to `http://127.0.0.1:10099/download/7.PNG` to confirm file download functionality. (While it is possible to download from the listing page, use the API directly to test the download function.)

``` # Download with wget; file size should match expected size [root@vbox ~] $ wget http://127.0.0.1:10099/download/7.PNG --2024-11-04 08:59:27-- http://127.0.0.1:10099/download/7.PNG Connecting to 127.0.0.1:10099... connected. HTTP request sent, awaiting response... 200 OK Length: 66662 (65K) [application/octet-stream] Saving to: `7.PNG'

7.PNG 100%[=====================================================================>] 65.10K --.-KB/s in 0s

2024-11-04 08:59:27 (397 MB/s) - `7.PNG' saved [66662/66662] ```


Related Links


Recommended Link


댓글

이 블로그의 인기 게시물

[로스트아크] 제작 효율 최적화 위한 영지 세팅

[로스트아크] 로스트아크 생활 도구 옵션

한국 핵무장 논의와 방위산업 관련주: 핵무기 개발 과정과 유망 종목 분석