Hi 👋, I'm coalooball

将写好的 mdBook 自动部署到 GitHub 仓库的 gh-pages 分支

关联问题

Publishing mdBook on Github Page

解决方法

Automated Deployment: GitHub Actions

笔者言

解决方法里有一些需要配置 Action, 可以按照这一小节Raw Example

在 mdBook 根目录创建文件 .github/workflows/deploy.yml。每次修改推送后, GitHub 会在当前分支和 gh-pages 分支进行CI/CD, 部署成功后即可在路由 https://<GitHub用户名>.github.io/<仓库名>/ 看到写好的 mdBook !

YMAL File for Deploy
name: Deploy
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write  # To push a branch 
      pull-requests: write  # To create a PR from that branch
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Install latest mdbook
      run: |
        tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
        url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
        mkdir mdbook
        curl -sSL $url | tar -xz --directory=./mdbook
        echo `pwd`/mdbook >> $GITHUB_PATH
    - name: Deploy GitHub Pages
      run: |
        # This assumes your book is in the root of your repository.
        # Just add a `cd` here if you need to change to another directory.
        mdbook build
        git worktree add gh-pages
        git config user.name "Deploy from CI"
        git config user.email ""
        cd gh-pages
        # Delete the ref to avoid keeping history.
        git update-ref -d refs/heads/gh-pages
        rm -rf *
        mv ../book/* .
        git add .
        git commit -m "Deploy $GITHUB_SHA to gh-pages"
        git push --force --set-upstream origin gh-pages

Actix

记录与 Actix 相关的开发代码。

Actix 官方没有描述如何上传文件, 以下是参考网友的资料整理的。
为了简洁, 将环境配置相关信息放到文章最后了。

上传一个文件

这段代码是改写actix-multipart页面的示例的。

use std::io::Read;
use actix_web::{post, App, HttpServer, Responder};
use actix_multipart::form::{tempfile::TempFile, MultipartForm};

#[derive(Debug, MultipartForm)]
struct UploadForm {
    #[multipart(limit = "100MB")]
    file: TempFile,
}

#[post("/upload")]
pub async fn upload(MultipartForm(mut form): MultipartForm<UploadForm>) -> impl Responder {
    // 获得文件 Bytes
    let mut buffer = vec![];
    let _ = form.file.file.read_to_end(&mut buffer);
    format!(
        "Uploaded file {:?}, with size: {}",
        form.file.file_name, form.file.size
    )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(move || App::new().service(upload))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

请求

require "uri"
require "net/http"
url = URI("http://127.0.0.1:8080/upload")
http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
form_data = [['file', File.open("/file/path")]]
request.set_form form_data, 'multipart/form-data'
response = http.request(request)
puts response.read_body

上传文件并且添加描述信息

use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm};
use actix_web::{post, App, HttpServer, Responder};

#[derive(Debug, MultipartForm)]
struct UploadForm {
    #[multipart(limit = "100MB")]
    file: TempFile,
    desc: Text<String>,
}

#[post("/upload")]
pub async fn upload(MultipartForm(form): MultipartForm<UploadForm>) -> impl Responder {
    format!(
        "Uploaded file {:?}, with size: {}, description: {:?}",
        form.file.file_name, form.file.size, form.desc
    )
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(move || App::new().service(upload))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

请求

require "uri"
require "net/http"

url = URI("http://127.0.0.1:8080/upload")

http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
form_data = [['file', File.open('/file/path')],['desc', "example"]]
request.set_form form_data, 'multipart/form-data'
response = http.request(request)
puts response.read_body

上传多个文件(一个参数里传输多个文件)

这个笔者没有找到相关资料, 是笔者自己试出来的代码。

use actix_multipart::form::{tempfile::TempFile, MultipartForm};
use actix_web::{post, App, HttpServer, Responder};

#[derive(Debug, MultipartForm)]
struct UploadForm {
    #[multipart(limit = "100MB")]
    file: Vec<TempFile>,
}

#[post("/upload")]
pub async fn upload(MultipartForm(form): MultipartForm<UploadForm>) -> impl Responder {
    let mut s = String::new();
    for f in form.file {
        s.push_str(&format!(
            "Uploaded file {:?}, with size: {} \n",
            f.file_name, f.size
        ))
    }
    s
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(move || App::new().service(upload))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

请求

require "uri"
require "net/http"
url = URI("http://127.0.0.1:8080/upload")
http = Net::HTTP.new(url.host, url.port);
request = Net::HTTP::Post.new(url)
form_data = [['file', File.open('/file1')],['file', File.open('/file2')]]
request.set_form form_data, 'multipart/form-data'
response = http.request(request)
puts response.read_body

环境配置

版本信息

rustc --version
# => rustc 1.80.1 (3f5fd8dd4 2024-08-06)
cargo --version
# => cargo 1.80.1 (376290515 2024-07-16)

Crates

创建空目录, 初始化项目。添加 crate :

cargo add actix-web
cargo add actix-multipart

Cargo.toml

[package]
name = "test1"
version = "0.1.0"
edition = "2021"

[dependencies]
actix-multipart = "0.7.2"
actix-web = "4.9.0"

参考

File upload in Actix Web
actix-multipart