文件上传-通过表单上传

1 前端:

我们先看表单上传文件的请求协议:

补充: 下文 [Content of aaa.txt] 代表文件数据.
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=boundary123

--boundary123
Content-Disposition: form-data; name="file"; filename="aaa.txt"
Content-Type: text/plain

[Content of aaa.txt]

--boundary123
Content-Disposition: form-data; name="file"; filename="bbb.tar"
Content-Type: application/x-tar

[Content of bbb.tar]

--boundary123
Content-Disposition: form-data; name="file"; filename="ccc.zip"
Content-Type: application/zip

[Content of ccc.zip]
--boundary123--
通过协议可以看到文件上传的核心是下面三部分:
请求方式: POST
内容类型: Content-Type: multipart/form-data; boundary=boundary123

具体文件数据: [Content of 文件数据]
我们需要在代码中给全这三部分.

前端通过表单上传文件:

angular:

html:

<form (submit)="upload(myUploadFiles.files)">
  <input type="file" name="file" #myUploadFiles multiple>
  <button type="submit">上传文件</button>
</form>

ts:

  upload(fileList: FileList | null) {
    if (fileList) {
      const formData = new FormData();
      for (let i = 0; i < fileList.length; i++) {
        formData.append(files[i].name, fileList[i]);
      }

      this.http.post('/api/upload/', formData).subscribe(
        (res) => {
          console.log('上传成功', res);
        },
        (error) => {
          console.error('上传失败', error);
        },
      );
    }
  }

2 后端 :

后端采用 rust actix_web 框架:

Cargo.toml

actix-web = { version = "4", features = ["openssl"] }
openssl = { version = "0.10", features = ["v110"] }
tokio = { version = "1.38.0", features = ["full"] }
async-stream = "0.3"
futures-util = "0.3.30"
actix-multipart = "0.4"

rust

use actix_web::{
    http::header::{ContentDisposition, ContentType, DispositionParam, DispositionType, HeaderValue}, 
    get, post, web, Error, App, HttpRequest, HttpResponse, HttpServer, Responder,
};
use std::path::Path;
use tokio::io::AsyncReadExt;
use openssl::ssl::{SslFiletype, SslAcceptor, SslMethod};
use actix_multipart::Multipart;
use tokio::io::AsyncWriteExt;
use futures_util::StreamExt;
use tokio::fs;


#[actix_web::main] async fn main() -> std::io::Result<()> { let addr = "127.0.0.1:8888"; println!("准备监听: {}", addr); let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); builder .set_private_key_file( "D:\\server.key", SslFiletype::PEM, ) .unwrap(); builder .set_certificate_chain_file("D:\\server.crt") .unwrap(); HttpServer::new(|| { App::new() .service(my_download) .service(my_upload) }) .bind_openssl(addr, builder)? .run() .await }

#[post("/api/upload")]
async fn my_upload(mut payload: Multipart) -> Result<HttpResponse, Error> {
    println!("文件上传被触发");
    while let Some(item) = payload.next().await {
        let mut field = item?;

        // Generate a unique file name
        // let filename = format!("upload_{}", "my_test");
        let filename = field.content_disposition().get_filename().unwrap();
        println!("{}", filename);
        // File path where the file will be saved
        let filepath = format!("F:/{}", filename);

        // Create file
        let mut f = fs::File::create(filepath).await?;

        // Write file contents
        while let Some(chunk) = field.next().await {
            let data = chunk?;
            f.write_all(&data).await?;
        }
    }

    Ok(HttpResponse::Ok().body("{\"upload\": \"File uploaded success\"}"))
}

 

 

posted on 2024-06-14 13:36  书源  阅读(41)  评论(0编辑  收藏  举报

导航