# web server 筆記 ## 使用的框架 伺服器使用 Nginx 前端使用 react, node.js, npm, JS語言 後端使用 flask ## Flask相關指令 開始 Flask ``` sudo systemctl start flask.service ``` 開機啟動 Flask ``` sudo systemctl enable flask.service ``` 查看 Flask 狀態 ``` sudo systemctl status flask.service ``` 重啟 Flask ``` sudo systemctl restart flask.service ``` 使用 flask 啟動程序 ``` flask run flask run --debug flask run --host=0.0.0.0 --port=5000 ``` `sudo systemctl daemon-reload` 你新增或刪除了 Systemd 的服務文件後需要重須啟動。 注意:這不會立即啟動或重啟服務,只是讓 Systemd 更新服務的配置。 `sudo lsof -i :5000` 查看在 Port 5000 上運行的服務 ### Notice 不管何時,如果你嘗試 debug Flask Server。使用 curl 去嘗試是個好主意。 如果跑在Port 5000,通過本地訪問 ``` curl http://127.0.0.1:5000 ``` 如果使用 Nginx 反向代理,使用 ``` curl http://141.147.150.224/service5000/ ``` 另一個例子 ``` curl http://141.147.150.224/service5000/api/get_dashboard_data ``` 嘗試重開 ``` sudo systemctl restart flask.service ``` ### 配置後台運行 ``` sudo vim /etc/systemd/system/flask.service ```` :::success ``` [Unit] Description=Flask App After=network.target [Service] User=ubuntu WorkingDirectory=/home/ubuntu ExecStart=/usr/bin/python3 /home/ubuntu/app.py Restart=always [Install] WantedBy=multi-user.target ``` ::: 然後重開 ``` sudo systemctl daemon-reload sudo systemctl restart flask.service ``` ### `python3 app.py` 當 Server 出現問題時,無法跑起來。可以手動跑跑看,這樣會出現錯誤信息。 ## react 指令 ### 套件 `create-react-app` 可以幫你生出一套框架,並安裝一些東西。 ## 各種安裝指令 安裝 Flask ``` pip install flask flask-cors ``` 安裝 react 的 axios,一個Http庫 ``` npm install axios ``` ## 防火牆指令 允許Port 5000 ``` sudo ufw allow 5000 ``` 不允許 Port 5000 ``` sudo ufw deny 5000 ``` 查看防火牆 ``` sudo ufw status ``` 重啟防火牆 ``` sudo ufw reload ``` ## Nginx 安裝 ``` sudo apt update && sudo apt upgrade -y sudo apt install nginx -y sudo systemctl start nginx sudo systemctl enable nginx ``` ## 啟動 pyhton 虛擬環境 ``` sudo apt install python3-venv source venv/bin/activate python3 -m venv venv ``` 最後一個venv是名稱,可以自己改。 ## Nodejs 安裝 安裝 Node Package Manager ``` sudo apt install npm node -v 建議版本要是Node 14 or Higher。 npm -v ``` 更新 Node.js ``` sudo apt update sudo apt upgrade curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs node -v npm -v ``` `npm install react-router-dom` 路由解決方案,用於解決頁面切換 ``` npm install @tanstack/react-query --legacy-peer-deps npm install @tanstack/react-query-devtools --legacy-peer-deps ``` 安裝 React Query ## nodejs 指令 ``` sudo npm isntall ``` sudo npm install 會尋找文件 package.json 去下載。 ``` npm run build ``` 使用 npm run build 來構件靜態網站,類似於編譯。 ``` sudo chown -R $USER:$USER ~/.npm ``` 修改 ~/.npm 權限,從root擁有變為$USER擁有 固定會議室 https://meet.google.com/aas-rfvw-afo 觀測cpu cat /proc/cpuinfo | grep "MHz" watch -n 1 "grep 'MHz' /proc/cpuinfo" ## 框架內容 `package.json` 一份 json文件,有一些配置資料。使用 `npm install`來安裝配置。 `package-lock.json` 一份18k行的json文件,儲存套件資料。 `public/index.html` 主要的html。 `src/index.js` 使用了 App, styles.css 的文件。 `src/styles.css` 一個 css 設定檔。 `src/App.js` src/components/FileUpload.js ## 以下未整理 伺服器傳送 const exectureable = [ { title: 'Cabbage', executable_name: 'Asd', input_num: 3 }, ]; 伺服器接收 const exectureable = [ { executable_name: 'Asd', input_num: 3, input_data1: 1, input_data2: 2, input_data3: 3 }, ]; # 變成 string ``` <pre>{JSON.stringify(data, null, 2)}<\pre> <script> async function fetchData() { try { const response = await fetch("http://141.147.150.224/service5000/api/data"); if (!response.ok) { throw new Error("Network response was not ok"); } const data = await response.json(); document.getElementById("output").innerText = data.message; } catch (error) { document.getElementById("output").innerText = `Error: ${error.message}`; } } </script> ``` 與伺服器進行數據傳輸的函數的命名規則 get 取得 fetch 取得 post 提交 update 更新 delete 刪除 /api/save_dashboard_data /api/get_dashboard_data /api/upload_executable 使用 curl server接收 ``` curl -X POST -H "Content-Type: application/json" \ -d '{"key": "value"}' \ http://localhost:5000/save_dashboarddata ``` server傳送 ``` curl http://localhost/service5000/api/get_dashboard_data ``` 後端api驗證用戶 const handleLogin = async () => { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); const data = await response.json(); if (response.ok && data.token) { localStorage.setItem('token', data.token); // 保存 token navigate('/dashboard'); } else { alert('Login Failed'); } }; Mutation更新數據 import React from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; const postData = async (newData) => { const response = await fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newData), }); if (!response.ok) { throw new Error('Failed to post data'); } return response.json(); }; const AddDataButton = () => { const queryClient = useQueryClient(); const mutation = useMutation(postData, { onSuccess: () => { queryClient.invalidateQueries(['serverData']); // 更新數據後重新拉取 }, }); const handleClick = () => { mutation.mutate({ name: 'New Item' }); }; return ( <button onClick={handleClick} disabled={mutation.isLoading}> {mutation.isLoading ? 'Adding...' : 'Add Data'} </button> ); }; export default AddDataButton; 當前的組件和函數 <FileUpload SERVER_IP={SERVER_IP} /> const postData = async (url, newData) => { const AddExecutableButton = () => { const DashboardPage = () => { async function fetchDashboardData () { const LoginPage = () => { const dashboard_component = ({ title, executable_name, input_num }) => { 一開始會到login page 然後到dashboard,dashboard會請求資料,並使用dashboard_component和FileUpload渲染。 當點擊FileUpload,進入新畫面,有Title,輸入框,參數數量,輸入框,可執行檔路徑,傳送資料