主頁 > 後端開發 > Rust Web 全堆疊開發之撰寫 WebAssembly 應用

Rust Web 全堆疊開發之撰寫 WebAssembly 應用

2023-06-05 07:51:08 後端開發

Rust Web 全堆疊開發之撰寫 WebAssembly 應用

MDN Web Docs:https://developer.mozilla.org/zh-CN/docs/WebAssembly

官網:https://webassembly.org/

專案結構 和 功能

Web App 教師注冊 <-> WebService <-> WebAssembly App 課程管理

什么是 WebAssembly

  • WebAssembly 是一種新的編碼方式,可以在現代瀏覽器中運行
    • 它是一種低級的類匯編語言
    • 具有緊湊的二進制格式
    • 可以接近原生的性能運行
    • 并為 C/C ++ 、 C# 、 Rust 等語言提供一個編譯目標,以便它們可以在 Web上運行
    • 它也被設計為可以與 JavaScript 共存,允許兩者一起作業,

機器碼

  • 機器碼是計算機可直接執行的語言
  • 匯編語言比較接近機器碼

ASSEMBLY -> ASSEMBLER -> MACHINE CODE

機器碼與 CPU 架構

  • 不同的 CPU 架構需要不同的機器碼和匯編
  • 高級語言可以“翻譯”成機器碼,以便在 CPU 上運行
  • SOURCE CODE
    • x64
    • x86
    • ARM

WebAssembly

  • WebAssembly 其實不是匯編語言,它不針對特定的機器,而是針對瀏覽器的,
  • WebAssembly 是中間編譯器目標
  • SOURCE CODE
    • WASM
      • x64
      • x86
      • ARM

WebAssembly 是什么樣的?

  • 文本格式 .wat
  • 二進制格式: .wasm

WebAssembly 能做什么

  • 可以把你撰寫 C/C++ 、 C# 、 Rust 等語言的代碼編譯成 WebAssembly 模塊
  • 你可以在 Web 應用中加載該模塊,并通過 JavaScript 呼叫它
  • 它并不是為了替代 JS ,而是與 JS 一起作業
  • 仍然需要 HTML 和 JS ,因為WebAssembly 無法訪問平臺 API ,例如 DOM , WebGL...

WebAssembly 如何作業

  • 這是 C/C++ 的例子

Hello.c -> EMSCRIPTEN(編譯器) -> hello.wasm hello.js hello.html

WebAssembly 的優點

  • 快速、高效、可移植
    • 通過利用常見的硬體能力, WebAssembly 代碼在不同平臺上能夠以接近本地速度運行,
  • 可讀、可除錯
    • WebAssembly 是一門低階語言,但是它有確實有一種人類可讀的文本格式(其標準最終版本目前仍在編制),這允許通過手工來寫代碼,看代碼以及除錯代碼,
  • 保持安全
    • WebAssembly 被限制運行在一個安全的沙箱執行環境中,像其他網路代碼一樣,它遵循瀏覽器的同源策略和授權策略,
  • 不破壞網路
    • WebAssembly 的設計原則是與其他網路技術和諧共處并保持向后兼容,

Rust WebAssembly 部分相關 crate

  • wasm-bindgen
  • wasm-bindgen-future
  • web-sys
  • js-sys

搭建環境

Rust 官網:https://www.rust-lang.org/zh-CN/what/wasm

Rust and WebAssembly:https://rustwasm.github.io/docs/book/

Rust和WebAssembly中文檔案:https://rustwasm.wasmdev.cn/docs/book/

安裝

wasm-pack

下載安裝地址:https://rustwasm.github.io/wasm-pack/installer/

Install wasm-pack

You appear to be running a *nix system (Unix, Linux, MacOS). Install by running:

curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

If you're not on *nix, or you don't like installing from curl, follow the alternate instructions below.

cargo-generate

cargo-generate helps you get up and running quickly with a new Rust project by leveraging a pre-existing git repository as a template.

Install cargo-generate with this command:

cargo install cargo-generate
~ via ?? base
? curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

info: downloading wasm-pack
info: successfully installed wasm-pack to `/Users/qiaopengjun/.cargo/bin/wasm-pack`

~ via ?? base took 8.9s
?

ws on  main via ?? 1.67.1 via ?? base took 23.7s
? cargo install cargo-generate

    Updating crates.io index
warning: spurious network error (2 tries remaining): failed to connect to github.com: Operation timed out; class=Os (2)
warning: spurious network error (1 tries remaining): failed to connect to github.com: Operation timed out; class=Os (2)
  Downloaded cargo-generate v0.18.3
  Downloaded 1 crate (94.7 KB) in 0.73s
	......
   Compiling git2 v0.17.2
   Compiling cargo-generate v0.18.3
    Finished release [optimized] target(s) in 3m 48s
  Installing /Users/qiaopengjun/.cargo/bin/cargo-generate
   Installed package `cargo-generate v0.18.3` (executable `cargo-generate`)

ws on  main via ?? 1.67.1 via ?? base took 3m 48.8s
? npm --version
9.5.0

ws on  main via ?? 1.67.1 via ?? base

Clone the Project Template

ws on  main via ?? 1.67.1 via ?? base
? cd ..

~/rust via ?? base
? cargo generate --git https://github.com/rustwasm/wasm-pack-template

??   Project Name: wasm-game-of-life
??   Destination: /Users/qiaopengjun/rust/wasm-game-of-life ...
??   project-name: wasm-game-of-life ...
??   Generating template ...
??   Moving generated files into: `/Users/qiaopengjun/rust/wasm-game-of-life`...
Initializing a fresh Git repository
?   Done! New project created /Users/qiaopengjun/rust/wasm-game-of-life

~/rust via ?? base took 21.2s
? cd wasm-game-of-life

wasm-game-of-life on  master [?] via ?? 1.67.1 via ?? base
? c

wasm-game-of-life on  master [?] via ?? 1.67.1 via ?? base
?

構建專案

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 1m 23.4s 
? wasm-pack build

[INFO]: ??  Checking for the Wasm target...
info: downloading component 'rust-std' for 'wasm32-unknown-unknown'
info: installing component 'rust-std' for 'wasm32-unknown-unknown'
[INFO]: ??  Compiling to Wasm...
   Compiling proc-macro2 v1.0.59
   Compiling unicode-ident v1.0.9
   Compiling quote v1.0.28
   Compiling wasm-bindgen-shared v0.2.86
   Compiling log v0.4.18
   Compiling bumpalo v3.13.0
   Compiling once_cell v1.17.2
   Compiling wasm-bindgen v0.2.86
   Compiling cfg-if v1.0.0
   Compiling syn v2.0.18
   Compiling wasm-bindgen-backend v0.2.86
   Compiling wasm-bindgen-macro-support v0.2.86
   Compiling wasm-bindgen-macro v0.2.86
   Compiling console_error_panic_hook v0.1.7
   Compiling wasm-game-of-life v0.1.0 (/Users/qiaopengjun/rust/wasm-game-of-life)
warning: function `set_panic_hook` is never used
 --> src/utils.rs:1:8
  |
1 | pub fn set_panic_hook() {
  |        ^^^^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `wasm-game-of-life` (lib) generated 1 warning
    Finished release [optimized] target(s) in 11.45s
[INFO]: ??  Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ?   Done in 1m 41s
[INFO]: ??   Your wasm pkg is ready to publish at /Users/qiaopengjun/rust/wasm-game-of-life/pkg.

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 1m 52.0s 
? 

問題

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.67.1 via ?? base took 3.8s 
? wasm-pack build

[INFO]: ??  Checking for the Wasm target...
Error: wasm32-unknown-unknown target not found in sysroot: "/opt/homebrew/Cellar/rust/1.67.1"

Used rustc from the following path: "/opt/homebrew/bin/rustc"
It looks like Rustup is not being used. For non-Rustup setups, the wasm32-unknown-unknown target needs to be installed manually. See https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.

Caused by: wasm32-unknown-unknown target not found in sysroot: "/opt/homebrew/Cellar/rust/1.67.1"

Used rustc from the following path: "/opt/homebrew/bin/rustc"
It looks like Rustup is not being used. For non-Rustup setups, the wasm32-unknown-unknown target needs to be installed manually. See https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.


wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.67.1 via ?? base 
? 

解決

https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html

電腦中有兩個Rust,默認使用的是brew install rust

通過 brew uninstall rust 卸載 Rust

并運行 rustup self uninstall 卸載通過官網安裝的 Rust

最后重新通過官網安裝Rust,再次執行命令解決問題,

Rust安裝

~ via ?? base
? curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

info: downloading installer

Welcome to Rust!

This will download and install the official compiler for the Rust
programming language, and its package manager, Cargo.

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  /Users/qiaopengjun/.rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory is located at:

  /Users/qiaopengjun/.cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  /Users/qiaopengjun/.cargo/bin

This path will then be added to your PATH environment variable by
modifying the profile files located at:

  /Users/qiaopengjun/.profile
  /Users/qiaopengjun/.bash_profile
  /Users/qiaopengjun/.zshenv

You can uninstall at any time with rustup self uninstall and
these changes will be reverted.

Current installation options:


   default host triple: aarch64-apple-darwin
     default toolchain: stable (default)
               profile: default
  modify PATH variable: yes

1) Proceed with installation (default)
2) Customize installation
3) Cancel installation
>1

info: profile set to 'default'
info: default host triple is aarch64-apple-darwin
info: syncing channel updates for 'stable-aarch64-apple-darwin'
info: latest update on 2023-06-01, rust version 1.70.0 (90c541806 2023-05-31)
info: downloading component 'cargo'
info: downloading component 'clippy'
info: downloading component 'rust-docs'
 13.5 MiB /  13.5 MiB (100 %)   4.6 MiB/s in  2s ETA:  0s
info: downloading component 'rust-std'
 25.5 MiB /  25.5 MiB (100 %)   4.9 MiB/s in  5s ETA:  0s
info: downloading component 'rustc'
 52.6 MiB /  52.6 MiB (100 %)   6.5 MiB/s in  8s ETA:  0s
info: downloading component 'rustfmt'
info: installing component 'cargo'
info: installing component 'clippy'
info: installing component 'rust-docs'
 13.5 MiB /  13.5 MiB (100 %)   7.9 MiB/s in  1s ETA:  0s
info: installing component 'rust-std'
 25.5 MiB /  25.5 MiB (100 %)  20.9 MiB/s in  1s ETA:  0s
info: installing component 'rustc'
 52.6 MiB /  52.6 MiB (100 %)  23.6 MiB/s in  2s ETA:  0s
info: installing component 'rustfmt'
info: default toolchain set to 'stable-aarch64-apple-darwin'

  stable-aarch64-apple-darwin installed - rustc 1.70.0 (90c541806 2023-05-31)


Rust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, run:
source "$HOME/.cargo/env"

~ via ?? base took 2m 46.4s
? source "$HOME/.cargo/env"

~ via ?? base
? rustc --version
rustc 1.70.0 (90c541806 2023-05-31)

~ via ?? base
? rustup toolchain list
stable-aarch64-apple-darwin (default)

~ via ?? base
?

構建

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 1m 23.4s 
? wasm-pack build

[INFO]: ??  Checking for the Wasm target...
info: downloading component 'rust-std' for 'wasm32-unknown-unknown'
info: installing component 'rust-std' for 'wasm32-unknown-unknown'
[INFO]: ??  Compiling to Wasm...
   Compiling proc-macro2 v1.0.59
   Compiling unicode-ident v1.0.9
   Compiling quote v1.0.28
   Compiling wasm-bindgen-shared v0.2.86
   Compiling log v0.4.18
   Compiling bumpalo v3.13.0
   Compiling once_cell v1.17.2
   Compiling wasm-bindgen v0.2.86
   Compiling cfg-if v1.0.0
   Compiling syn v2.0.18
   Compiling wasm-bindgen-backend v0.2.86
   Compiling wasm-bindgen-macro-support v0.2.86
   Compiling wasm-bindgen-macro v0.2.86
   Compiling console_error_panic_hook v0.1.7
   Compiling wasm-game-of-life v0.1.0 (/Users/qiaopengjun/rust/wasm-game-of-life)
warning: function `set_panic_hook` is never used
 --> src/utils.rs:1:8
  |
1 | pub fn set_panic_hook() {
  |        ^^^^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `wasm-game-of-life` (lib) generated 1 warning
    Finished release [optimized] target(s) in 11.45s
[INFO]: ??  Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ?   Done in 1m 41s
[INFO]: ??   Your wasm pkg is ready to publish at /Users/qiaopengjun/rust/wasm-game-of-life/pkg.

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 1m 52.0s 
? 

Npm 初始化專案

npm 中文網:https://npm.nodejs.cn/

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 24.9s 
? npm init wasm-app www
?? Rust + ?? Wasm = ?

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 22.7s 
? 

www/package.json

{
  "name": "create-wasm-app",
  "version": "0.1.0",
  "description": "create an app to consume rust-generated wasm packages",
  "main": "index.js",
  "bin": {
    "create-wasm-app": ".bin/create-wasm-app.js"
  },
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack-dev-server"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/rustwasm/create-wasm-app.git"
  },
  "keywords": [
    "webassembly",
    "wasm",
    "rust",
    "webpack"
  ],
  "author": "Ashley Williams <[email protected]>",
  "license": "(MIT OR Apache-2.0)",
  "bugs": {
    "url": "https://github.com/rustwasm/create-wasm-app/issues"
  },
  "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
  "dependencies": {
    "wasm-game-of-life": "file:../pkg"
  },
  "devDependencies": {
    "hello-wasm-pack": "^0.1.0",
    "webpack": "^4.29.3",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5",
    "copy-webpack-plugin": "^5.0.0"
  }
}

安裝依賴

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 22.7s 
? cd www                                                               

www on  master [!] is ?? 0.1.0 via ? v19.7.0 via ?? base 
? npm install        

www/index.js

import * as wasm from "wasm-game-of-life";

wasm.greet();

運行

www on  master [!] is ?? 0.1.0 via ? v19.7.0 via ?? base took 2m 15.4s 
? npm run start

訪問:http://localhost:8080/

src/lib.rs

mod utils;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
extern {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet(s : &str) {
    alert(format!("Hello, {}!", s).as_str());
}

構建

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base 
? wasm-pack build
[INFO]: ??  Checking for the Wasm target...
[INFO]: ??  Compiling to Wasm...
   Compiling wasm-game-of-life v0.1.0 (/Users/qiaopengjun/rust/wasm-game-of-life)
warning: function `set_panic_hook` is never used
 --> src/utils.rs:1:8
  |
1 | pub fn set_panic_hook() {
  |        ^^^^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: `wasm-game-of-life` (lib) generated 1 warning
    Finished release [optimized] target(s) in 0.37s
[INFO]: ??  Installing wasm-bindgen...
[INFO]: Optimizing wasm binaries with `wasm-opt`...
[INFO]: Optional fields missing from Cargo.toml: 'description', 'repository', and 'license'. These are not necessary, but recommended
[INFO]: ?   Done in 0.80s
[INFO]: ??   Your wasm pkg is ready to publish at /Users/qiaopengjun/rust/wasm-game-of-life/pkg.

wasm-game-of-life on  master [?] is ?? 0.1.0 via ?? 1.70.0 via ?? base 
? 

安裝并運行

www on  master [!] is ?? 0.1.0 via ? v19.7.0 via ?? base took 8m 0.8s 
? npm install && npm run start
npm WARN deprecated [email protected]: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2

www/index.js

import * as wasm from "wasm-game-of-life";

wasm.greet("Dave");

打開專案 ws

webservice/Cargo.toml

[package]
name = "webservice"
version = "0.1.0"
edition = "2021"
default-run = "teacher-service"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
actix-cors = "0.6.4"
actix-web = "4.3.1"
actix-rt = "2.8.0"
dotenv = "0.15.0"
serde = { version = "1.0.163", features = ["derive"] }
chrono = { version = "0.4.24", features = ["serde"] }
openssl = { version = "0.10.52", features = ["vendored"] }
sqlx = { version = "0.6.3", default_features = false, features = [
    "postgres",
    "runtime-tokio-rustls",
    "macros",
    "chrono",
] }


[[bin]]
name = "teacher-service"

webservice/src/bin/teacher-service.rs

use actix_cors::Cors;
use actix_web::{http, web, App, HttpServer};
use dotenv::dotenv;
use sqlx::postgres::PgPoolOptions;
use std::env;
use std::io;
use std::sync::Mutex;

#[path = "../dbaccess/mod.rs"]
mod dbaccess;
#[path = "../errors.rs"]
mod errors;
#[path = "../handlers/mod.rs"]
mod handlers;
#[path = "../models/mod.rs"]
mod models;
#[path = "../routers.rs"]
mod routers;
#[path = "../state.rs"]
mod state;

use errors::MyError;
use routers::*;
use state::AppState;

#[actix_rt::main]
async fn main() -> io::Result<()> {
    dotenv().ok();

    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL is not set.");
    let db_pool = PgPoolOptions::new().connect(&database_url).await.unwrap();
    let shared_data = web::Data::new(AppState {
        health_check_response: "I'm Ok.".to_string(),
        visit_count: Mutex::new(0),
        db: db_pool,
    });
    let app = move || {
        let cors = Cors::default()
            .allowed_origin("http://localhost:8080/")
            .allowed_origin_fn(|origin, _req_head| {
                origin.as_bytes().starts_with(b"http://localhost")
            })
            .allowed_methods(vec!["GET", "POST", "DELETE"])
            .allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
            .allowed_header(http::header::CONTENT_TYPE)
            .max_age(3600);

        App::new()
            .app_data(shared_data.clone())
            .app_data(web::JsonConfig::default().error_handler(|_err, _req| {
                MyError::InvalidInput("Please provide valid json input".to_string()).into()
            }))
            .configure(general_routes)
            .configure(course_routes) // 路由注冊
            .wrap(cors)
            .configure(teacher_routes)
    };

    HttpServer::new(app).bind("127.0.0.1:3000")?.run().await
}

Wasm 克隆專案模板

ws on  main via ?? 1.70.0 via ?? base 
? cargo generate --git https://github.com/rustwasm/wasm-pack-template

??   Project Name: wasm-client
??   Destination: /Users/qiaopengjun/rust/ws/wasm-client ...
??   project-name: wasm-client ...
??   Generating template ...
??   Moving generated files into: `/Users/qiaopengjun/rust/ws/wasm-client`...
Initializing a fresh Git repository
?   Done! New project created /Users/qiaopengjun/rust/ws/wasm-client

ws on  main [!?] via ?? 1.70.0 via ?? base took 29.2s 
? 

Npm 初始化專案

ws/wasm-client on  main [!?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 11.9s 
? npm init wasm-app www
?? Rust + ?? Wasm = ?

ws/wasm-client on  main [!?] is ?? 0.1.0 via ?? 1.70.0 via ?? base took 3.5s 
? 

構建專案

wasm-pack build

Cargo.toml

[workspace]
members = ["webservice", "webapp", "wasm-client"]

wasm-client/Cargo.toml

[package]
name = "wasm-client"
version = "0.1.0"
authors = ["QiaoPengjun5162 <[email protected]>"]
edition = "2018"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
default = ["console_error_panic_hook"]

[dependencies]
chrono = { version = "0.4.26", features = ["serde"] }
serde = { version = "1.0.163", features = ["derive"] }
serde_derive = "1.0.163"
serde_json = "1.0.96"
js-sys = "0.3.63"
wasm-bindgen = { version = "0.2.86", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.36"
web-sys = { version = "0.3.63", features = [
    "Headers",
    "Request",
    "RequestInit",
    "RequestMode",
    "Response",
    "Window",
    "Document",
    "Element",
    "HtmlElement",
    "Node",
    "console",
] }

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.6", optional = true }

# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
wee_alloc = { version = "0.4.5", optional = true }

[dev-dependencies]
wasm-bindgen-test = "0.3.13"

[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"

注意:并不是所有的 Rust crate 都能在wasm中使用

https://getbootstrap.com/docs/5.2/getting-started/introduction/#cdn-links

專案目錄

ws on  main [!?] via ?? 1.70.0 via ?? base 
? tree -a -I "target|.git|node_modules|.bin"
.
├── .env
├── .gitignore
├── .vscode
│   └── settings.json
├── Cargo.lock
├── Cargo.toml
├── README.md
├── wasm-client
│   ├── .appveyor.yml
│   ├── .gitignore
│   ├── .travis.yml
│   ├── Cargo.toml
│   ├── LICENSE_APACHE
│   ├── LICENSE_MIT
│   ├── README.md
│   ├── pkg
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── wasm_client.d.ts
│   │   ├── wasm_client.js
│   │   ├── wasm_client_bg.js
│   │   ├── wasm_client_bg.wasm
│   │   └── wasm_client_bg.wasm.d.ts
│   ├── src
│   │   ├── errors.rs
│   │   ├── lib.rs
│   │   ├── models
│   │   │   ├── course.rs
│   │   │   └── mod.rs
│   │   └── utils.rs
│   ├── tests
│   │   └── web.rs
│   └── www
│       ├── .gitignore
│       ├── .travis.yml
│       ├── LICENSE-APACHE
│       ├── LICENSE-MIT
│       ├── README.md
│       ├── bootstrap.js
│       ├── index.html
│       ├── index.js
│       ├── package-lock.json
│       ├── package.json
│       └── webpack.config.js
├── webapp
│   ├── .env
│   ├── Cargo.toml
│   ├── src
│   │   ├── bin
│   │   │   └── svr.rs
│   │   ├── errors.rs
│   │   ├── handlers.rs
│   │   ├── mod.rs
│   │   ├── models.rs
│   │   └── routers.rs
│   └── static
│       ├── css
│       │   └── register.css
│       ├── register.html
│       └── teachers.html
└── webservice
    ├── Cargo.toml
    └── src
        ├── bin
        │   └── teacher-service.rs
        ├── dbaccess
        │   ├── course.rs
        │   ├── mod.rs
        │   └── teacher.rs
        ├── errors.rs
        ├── handlers
        │   ├── course.rs
        │   ├── general.rs
        │   ├── mod.rs
        │   └── teacher.rs
        ├── main.rs
        ├── models
        │   ├── course.rs
        │   ├── mod.rs
        │   └── teacher.rs
        ├── routers.rs
        └── state.rs

19 directories, 65 files

ws on  main [!?] via ?? 1.70.0 via ?? base 
? 

wasm-client/www/package.json

{
  "name": "create-wasm-app",
  "version": "0.1.0",
  "description": "create an app to consume rust-generated wasm packages",
  "main": "index.js",
  "bin": {
    "create-wasm-app": ".bin/create-wasm-app.js"
  },
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "start": "webpack-dev-server"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/rustwasm/create-wasm-app.git"
  },
  "keywords": [
    "webassembly",
    "wasm",
    "rust",
    "webpack"
  ],
  "author": "Ashley Williams <[email protected]>",
  "license": "(MIT OR Apache-2.0)",
  "bugs": {
    "url": "https://github.com/rustwasm/create-wasm-app/issues"
  },
  "homepage": "https://github.com/rustwasm/create-wasm-app#readme",
  "dependencies": {
    "wasm-client": "file:../pkg"
  },
  "devDependencies": {
    "hello-wasm-pack": "^0.1.0",
    "webpack": "^4.29.3",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5",
    "copy-webpack-plugin": "^5.0.0"
  }
}

wasm-client/src/errors.rs

use serde::Serialize;

#[derive(Debug, Serialize)]
pub enum MyError {
    SomeError(String),
}

impl From<String> for MyError {
    fn from(s: String) -> Self {
        MyError::SomeError(s)
    }
}

impl From<wasm_bindgen::JsValue> for MyError {
    fn from(js_value: wasm_bindgen::JsValue) -> Self {
        MyError::SomeError(js_value.as_string().unwrap())
    }
}

wasm-client/src/models/mod.rs

pub mod course;

wasm-client/src/models/course.rs

use super::super::errors::MyError;
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};

#[derive(Debug, Deserialize, Serialize)]
pub struct Course {
    pub teacher_id: i32,
    pub id: i32,
    pub name: String,
    pub time: NaiveDateTime,

    pub description: Option<String>,
    pub format: Option<String>,
    pub structure: Option<String>,
    pub duration: Option<String>,
    pub price: Option<i32>,
    pub language: Option<String>,
    pub level: Option<String>,
}

pub async fn get_courses_by_teacher(teacher_id: i32) -> Result<Vec<Course>, MyError> {
    // 訪問webservice 讀取課程
    let mut opts = RequestInit::new();
    opts.method("GET");
    opts.mode(RequestMode::Cors); // 跨域

    let url = format!("http://localhost:3000/courses/{}", teacher_id);

    let request = Request::new_with_str_and_init(&url, &opts)?;
    request.headers().set("Accept", "application/json")?;

    let window = web_sys::window().ok_or("no window exists".to_string())?;
    let resp_value = https://www.cnblogs.com/QiaoPengjun/archive/2023/06/04/JsFuture::from(window.fetch_with_request(&request)).await?;

    assert!(resp_value.is_instance_of::());

    let resp: Response = resp_value.dyn_into().unwrap();
    let json = JsFuture::from(resp.json()?).await?;

    // let courses: Vec = json.into_serde().unwrap();
    let courses: Vec = serde_wasm_bindgen::from_value(json).unwrap();

    Ok(courses)
}

pub async fn delete_course(teacher_id: i32, course_id: i32) -> () {
    let mut opts = RequestInit::new();
    opts.method("DELETE");
    opts.mode(RequestMode::Cors);

    let url = format!("http://localhost:3000/courses/{}/{}", teacher_id, course_id);

    let request = Request::new_with_str_and_init(&url, &opts).unwrap();
    request.headers().set("Accept", "application/json").unwrap();

    let window = web_sys::window().unwrap();
    let resp_value = https://www.cnblogs.com/QiaoPengjun/archive/2023/06/04/JsFuture::from(window.fetch_with_request(&request))
        .await
        .unwrap();

    assert!(resp_value.is_instance_of::());

    let resp: Response = resp_value.dyn_into().unwrap();
    let json = JsFuture::from(resp.json().unwrap()).await.unwrap();

    // let _course: Course = json.into_serde().unwrap();
    let _courses: Course = serde_wasm_bindgen::from_value(json).unwrap();
}

use js_sys::Promise;
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub async fn add_course(name: String, description: String) -> Result {
    let mut opts = RequestInit::new();
    opts.method("POST");
    opts.mode(RequestMode::Cors);
    let str_json = format!(
        r#"
        {{
            "teacher_id": 1,
            "name": "{}",
            "description": "{}"
        }}
        "#,
        name, description
    );
    opts.body(Some(&JsValue::from_str(str_json.as_str())));
    let url = "http://localhost:3000/courses/";

    let request = Request::new_with_str_and_init(&url, &opts)?;
    request.headers().set("Content-Type", "application/json")?;
    request.headers().set("Accept", "application/json")?;

    let window = web_sys::window().ok_or("no window exists".to_string())?;
    let resp_value = https://www.cnblogs.com/QiaoPengjun/archive/2023/06/04/JsFuture::from(window.fetch_with_request(&request))
        .await
        .unwrap();

    assert!(resp_value.is_instance_of::());

    let resp: Response = resp_value.dyn_into().unwrap();
    Ok(resp.json()?)
}

wasm-client/src/lib.rs

mod utils;

use wasm_bindgen::prelude::*;

// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
// allocator.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
    fn confirm(s: &str) -> bool;

    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[wasm_bindgen]
pub fn greet(_name: &str) {
    alert("Hello, wasm-client!");
}

pub mod errors;
pub mod models;

use models::course::{delete_course, get_courses_by_teacher, Course};
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::*;
use web_sys::HtmlButtonElement;

#[wasm_bindgen(start)]
pub async fn main() -> Result<(), JsValue> {
    let window = web_sys::window().expect("no global window exists");
    let document = window.document().expect("no global document exists");

    let left_tbody = document
        .get_element_by_id("left-tbody")
        .expect("left div not exists");

    let courses: Vec<Course> = get_courses_by_teacher(1).await.unwrap();
    for c in courses.iter() {
        let tr = document.create_element("tr")?;
        tr.set_attribute("id", format!("tr-{}", c.id).as_str())?;
        let td = document.create_element("td")?;
        td.set_text_content(Some(format!("{}", c.id).as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        td.set_text_content(Some(c.name.as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        td.set_text_content(Some(c.time.format("%Y-%m-%d").to_string().as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        if let Some(desc) = c.description.clone() {
            td.set_text_content(Some(desc.as_str()));
        }
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        // let btn = document.create_element("button")?;
        let btn: HtmlButtonElement = document
            .create_element("button")
            .unwrap()
            .dyn_into::<HtmlButtonElement>()
            .unwrap();

        let cid = c.id;
        let click_closure = Closure::wrap(Box::new(move |_event: web_sys::MouseEvent| {
            let r = confirm(format!("確認洗掉 ID 為 {} 的課程?", cid).as_str());
            match r {
                true => {
                    spawn_local(delete_course(1, cid)); // delete_course 異步函式 spawn_local 把 future 放在當前執行緒
                    alert("洗掉成功!");

                    web_sys::window().unwrap().location().reload().unwrap();
                }
                _ => {}
            }
        }) as Box<dyn Fn(_)>);

        btn.add_event_listener_with_callback("click", click_closure.as_ref().unchecked_ref())?; // 要把閉包轉化為 function 的參考
        click_closure.forget(); // 走出作用域后函式依然有效 但會造成記憶體泄漏

        btn.set_attribute("class", "btn btn-danger btn-sm")?;
        btn.set_text_content(Some("Delete"));
        td.append_child(&btn)?;
        tr.append_child(&td)?;

        left_tbody.append_child(&tr)?;
    }

    Ok(())
}

wasm-client/www/index.js

import * as wasm from "wasm-client";

const myForm = document.getElementById('form');
myForm.addEventListener('submit', (e) => {
  e.preventDefault();
  const name = document.getElementById('name').value;
  const desc = document.querySelector('#description').value;

  wasm.add_course(name, desc).then((json) => {
    alert("添加成功!");
    window.location.reload();
  });
});

wasm-client/www/index.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Hello wasm-pack!</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous" />
</head>

<body>
  <noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
  <nav >
    <div >
      <a  href="https://www.cnblogs.com/QiaoPengjun/archive/2023/06/04/#">Wasm-client</a>
    </div>
  </nav>
  <div  style="height: 600px">
    <div >
      <div >
        <div >
          <div >課程串列</div>
          <!-- <div >
            <button type="button" >Add</button>
          </div> -->
          <table >
            <thead>
              <tr>
                <th scope="col">ID</th>
                <th scope="col">名稱</th>
                <th scope="col">時間</th>
                <th scope="col">簡介</th>
                <th scope="col">操作</th>
              </tr>
            </thead>
            <tbody id="left-tbody"></tbody>
          </table>
          <div id="left"></div>
        </div>
      </div>
      <div >
        <div >
          <div >添加課程</div>
          <div >
            <form  id="form">
              <div >
                <label for="name" >課程名稱</label>
                <input type="name"  id="name" required placeholder="課程名稱" />
                <div >
                  請填寫課程名!
                </div>
              </div>
              <div >
                <label for="description" >課程簡介</label>
                <textarea  id="description" rows="3"></textarea>
              </div>
              <div >
                <button type="submit" >提交</button>
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
  <script src="https://www.cnblogs.com/QiaoPengjun/archive/2023/06/04/bootstrap.js"></script>
</body>

</html>

運行

ws/wasm-client on  main [!?] is ?? 0.1.0 via ?? 1.70.0 via ?? base 
? wasm-pack build           

ws/webservice on  main [!?] is ?? 0.1.0 via ?? 1.70.0 via ?? base 
? cargo run    

www on  master [!] is ?? 0.1.0 via ? v19.7.0 via ?? base 
? npm install && npm run start

訪問:http://localhost:8080/

問題:報錯 Uncaught (in promise) DOMException: Failed to execute 'appendChild' on 'Node': The new child element contains the parent. 前端獲取不到課程資訊

解決:

這個錯誤提示說明在嘗試將一個元素添加為其父元素的子元素時出現了問題,導致了回圈參考,具體來說,錯誤發生在這一行代碼中:

td.append_child(&td)?;

在這行代碼中,你試圖將創建的td元素添加為其自身的子元素,這是不允許的,因為一個元素不能成為自己的子元素,

正確的代碼是: tr.append_child(&td)?;

修改之后的代碼:

#[wasm_bindgen(start)]
pub async fn main() -> Result<(), JsValue> {
    let window = web_sys::window().expect("no global window exists");
    let document = window.document().expect("no global document exists");

    let left_tbody = document
        .get_element_by_id("left-tbody")
        .expect("left div not exists");

    let courses: Vec<Course> = get_courses_by_teacher(1).await.unwrap();
    for c in courses.iter() {
        let tr = document.create_element("tr")?;
        tr.set_attribute("id", format!("tr-{}", c.id).as_str())?;
        let td = document.create_element("td")?;
        td.set_text_content(Some(format!("{}", c.id).as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        td.set_text_content(Some(c.name.as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        td.set_text_content(Some(c.time.format("%Y-%m-%d").to_string().as_str()));
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        if let Some(desc) = c.description.clone() {
            td.set_text_content(Some(desc.as_str()));
        }
        tr.append_child(&td)?;

        let td = document.create_element("td")?;
        // let btn = document.create_element("button")?;
        let btn: HtmlButtonElement = document
            .create_element("button")
            .unwrap()
            .dyn_into::<HtmlButtonElement>()
            .unwrap();

        let cid = c.id;
        let click_closure = Closure::wrap(Box::new(move |_event: web_sys::MouseEvent| {
            let r = confirm(format!("確認洗掉 ID 為 {} 的課程?", cid).as_str());
            match r {
                true => {
                    spawn_local(delete_course(1, cid)); // delete_course 異步函式 spawn_local 把 future 放在當前執行緒
                    alert("洗掉成功!");

                    web_sys::window().unwrap().location().reload().unwrap();
                }
                _ => {}
            }
        }) as Box<dyn Fn(_)>);

        btn.add_event_listener_with_callback("click", click_closure.as_ref().unchecked_ref())?; // 要把閉包轉化為 function 的參考
        click_closure.forget(); // 走出作用域后函式依然有效 但會造成記憶體泄漏

        btn.set_attribute("class", "btn btn-danger btn-sm")?;
        btn.set_text_content(Some("Delete"));
        td.append_child(&btn)?;
        tr.append_child(&td)?;

        left_tbody.append_child(&tr)?;
    }

    Ok(())
}

本文來自博客園,作者:QIAOPENGJUN,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17455654.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/554259.html

標籤:其他

上一篇:包含參考型別欄位的自定義結構體,能作為map的key嗎

下一篇:返回列表

標籤雲
其他(160312) Python(38201) JavaScript(25475) Java(18185) C(15236) 區塊鏈(8269) C#(7972) AI(7469) 爪哇(7425) MySQL(7231) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5346) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4582) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1981) 功能(1967) HtmlCss(1952) Web開發(1951) C++(1928) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1879) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust Web 全堆疊開發之撰寫 WebAssembly 應用

    # Rust Web 全堆疊開發之撰寫 WebAssembly 應用 MDN Web Docs: 官網: ## 專案結構 和 功能 **Web App 教師注冊 WebService WebAssembly App 課程管理** ## 什么是 WebAssembly - WebAssembly 是一種 ......

    uj5u.com 2023-06-05 07:51:08 more
  • 包含參考型別欄位的自定義結構體,能作為map的key嗎

    # 1. 引言 在 Go 語言中,`map`是一種內置的資料型別,它提供了一種高效的方式來存盤和檢索資料。`map`是一種無序的鍵值對集合,其中每個鍵與一個值相關聯。使用 map 資料結構可以快速地根據鍵找到對應的值,而無需遍歷整個集合。 在 Go 語言中,`map` 是一種內置的資料型別,可以通過 ......

    uj5u.com 2023-06-05 07:51:00 more
  • p3 FileInputStream 和 FileOutputStream

    # FileInputStream 和 FileOutputStream ![](https://img2023.cnblogs.com/blog/3008601/202306/3008601-20230604102221520-1382311786.png) - InputStream:位元組輸入流 ......

    uj5u.com 2023-06-05 07:50:48 more
  • p2 IO流原理及流的分類

    # IO流原理及流的分類 ### 一、Java IO流原理 1. I/O是Input/Output的縮寫,I/O技術是非常實用的技術,用于處理資料傳輸。如讀/寫檔案,網路通訊等。 2. Java程式中,對于資料的輸入/輸出操作以”流(stream)“的方式進行。 3. java.io包下提供了各種” ......

    uj5u.com 2023-06-05 07:45:25 more
  • FHQ-Treap

    [模板傳送](https://www.luogu.com.cn/problem/P3369) FHQ-Treap顧名思義就是范浩強大佬設計的一種二叉平衡樹 下面我們來講一下它的原理和代碼 # 結構體 對于一個節點,我們需要記錄的是 * 對應的值 * 子樹節點數 * 左右孩子編號 * 對應的隨機值 ` ......

    uj5u.com 2023-06-05 07:40:15 more
  • p1 檔案的基本使用

    # 檔案的基本使用 ### 一、檔案 - **什么是檔案** 檔案是保存資料的地方,比如word檔案,txt檔案,excel檔案……都是檔案。即可以保存一張圖片,也可以保持視頻,聲音…… - **檔案流** 檔案在程式中是以流的形式來操作的 ![檔案流](https://img2023.cnblog ......

    uj5u.com 2023-06-05 07:40:06 more
  • Groovy 基于Groovy實作DES加解密

    groovy 3.0.7 ### DES加密簡介 加密分為對稱加密和非對稱加密。非對稱加密,加解密使用不同的密鑰,如RSA;對稱加密,加解密使用相同的密鑰,如DES(Data Encryption Standard,即資料加密標準)。相對而言,非對稱加密安全性更高,但是計算程序復雜耗時,一般只應用于 ......

    uj5u.com 2023-06-05 07:39:54 more
  • 【python基礎】復雜資料型別-串列型別(串列切片)

    # 1.串列切片 前面學習的是如何處理串列的所有資料元素。python還可以處理串列的部分元素,python稱之為切片。 ## 1.1創建切片 創建切片,可指定要使用的第一個資料元素的索引和最后一個資料元素的索引。與range函式一樣,python在到達指定的第二個索引前面的資料元素后停止。比如要輸 ......

    uj5u.com 2023-06-05 07:34:02 more
  • 基于ESP32的TCP/IP傳輸實作

    #TCP/IP協議原理 TCP/IP協議是Internet互聯網最基本的協議,TCP/IP協議的應用層的主要協議有HTTP、Telnet、FTP、SMTP等,是用來讀取來自傳輸層的資料或者將資料傳輸寫入傳輸層;傳輸層的主要協議有UDP、TCP,實作端對端的資料傳輸;網路層的主要協議有ICMP、IP、 ......

    uj5u.com 2023-06-04 07:46:19 more
  • 【python基礎】復雜資料型別-串列型別(排序/長度/遍歷)

    # 1.串列資料元素排序 在創建的串列中,資料元素的排列順序常常是無法預測的。這雖然在大多數情況下都是不可避免的,但經常需要以特定的順序呈現資訊。有時候希望保留串列資料元素最初的排列順序,而有時候又需要調整排列順序。python提供了很多串列資料元素排序的方式,可根據情況選用。 ## 1.永久性排序 ......

    uj5u.com 2023-06-04 07:45:59 more