尋找 public key 裡面的 text,並使用 cat
印出來,貼到 gitHub 的 add new SSH key 上。
> cd
> cd .ssh
> ls
> id_rsa id_rsa.pub
> cat id_rsa.pub
印出 id_rsa.pub 的 ssh key 之後,回到 gitHub 上,新增 SSH key 至 gitHub 上。
在 command line 上,先找到新增檔案的資料夾位置
> cd
> cd .ssh
> pwd # 查看路徑
> /Users/jeanlu/.ssh
使用 CLI generate SSH key
ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/jeanlu/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/jeanlu/.ssh/id_ed25519
Your public key has been saved in /Users/jeanlu/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx jeanlu@Jeans-macBook.local
The key's randomart image is:
+--[ED25519 256]--+
|oE.=..oo |
|=.+ =oo .. |
| O.B o o* + |
|=.B * o+ = . |
|.+ + + S |
| + o... |
| ...o.. |
| o. o.. |
| o+. .. |
+----[SHA256]-----+
新增好 key 之後,查看一下名稱,並複製到 gitHub 的 add new SSH key 上
> ls
> id_ed25519.pub id_ed25519
尋找 public key 裡面的 text,並使用 cat
印出來,貼到 gitHub 的 add new SSH key 上。
> cd
> cd .ssh
> ls
> id_rsa id_rsa.pub
> cat id_rsa.pub
印出 id_rsa.pub 的 ssh key 之後,回到 gitHub 上,新增 SSH key 至 gitHub 上。
在 command line 上,先找到新增檔案的資料夾位置
> cd
> cd .ssh
> pwd # 查看路徑
> /Users/jeanlu/.ssh
使用 CLI generate SSH key
ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/Users/jeanlu/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/jeanlu/.ssh/id_ed25519
Your public key has been saved in /Users/jeanlu/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx jeanlu@Jeans-macBook.local
The key's randomart image is:
+--[ED25519 256]--+
|oE.=..oo |
|=.+ =oo .. |
| O.B o o* + |
|=.B * o+ = . |
|.+ + + S |
| + o... |
| ...o.. |
| o. o.. |
| o+. .. |
+----[SHA256]-----+
新增好 key 之後,查看一下名稱,並複製到 gitHub 的 add new SSH key 上
> ls
> id_ed25519.pub id_ed25519
修改 .gitignore
檔案時,把 /node_modules
寫錯了,所以要 git push heroku
時,連同 /node_modules
也 push 上 Heroku 了。
$ heroku logs --tail
...(略)
2022-05-22T23:09:40.062420+00:00 app[web.1]: Error: /app/node_modules/bcrypt/lib/binding/bcrypt_lib.node: invalid ELF header
參考此篇bcrypt error when deploy on Heroku : invalid ELF header #595,發現可以由以下方法補救:
.gitignore
上寫上應該被 git 忽略的檔案// google .gitignore 的 template,並加以修改:
/node_modules
.env
...
$ git rm -r --cached .
$ git add .
$ git commit -m "fixed untracked files"
$ git push heroku
ERR_INVALID_ARG_TYPE(name, 'string', value);
heroku logs --tail
heroku express deployinternal/validators.js:124 throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
#### 2.2 問題修改./models/index.js
裡面有引用 process.env[var_name]
但沒有引入 dotenv
library,所以發生了問題,因此在此檔案內加:require("dotenv").config();
console.log(process.env[var_name]
,Heroku 仍沒有吃到 .env
的變數在檔案內印了 process.env
的變數,但 Heroku 在執行時,沒有印出來,應該是沒有吃到 .env 變數。
// console.log('process.env.JWT_EXPIRES_IN', process.env.JWT_EXPIRES_IN)
// console.log('process.env.JWT_SECRET', process.env.JWT_SECRET)
$ heroku logs --tail
2022-05-22T05:56:18.729657+00:00 app[web.1]: Error: secretOrPrivateKey must have a value
2022-05-22T05:56:18.729657+00:00 app[web.1]: process.env.JWT_EXPIRES_IN
process.env.JWT_SECRET
參考此篇 StackOverflow How to set environment variables on Heroku for Node app and connect to the PostgreSQL database?,我發現可以使用 CLI 來設定 config。
$ heroku config // 查詢 Heroku 有哪些環境變數
polar-tor-55391 Config Vars
CLEARDB_DATABASE_URL: mysql://<host>:<pwd>@<host>/<dataBase>?reconnect=true
$ heroku config:set DB_HOST=my_DB // 設定新的環境參數名稱及內容
這個方法可以直接輸入環境變數名稱及內容,與上述使用 CLI 建立的方法是一樣的。
一開始出現了跟資料庫連現有關的問題:
$ heroku logs --tail
2022-05-22T06:22:42.386671+00:00 app[web.1]: Ignoring invalid configuration option passed to Connection: reconnect. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection
在 Heroku 上部署,環境應是 production
,此時打開 ./config/config.js
:
因為我已經在 Heroku 上建立 ClearDB MySQL 了,Heroku 資料庫連線的基本資訊(username, password, host, database)都已經附在 Heroku > settings > Config Vars
內,所以只要加 use_env_variable: "CLEARDB_DATABASE_URL",
這行,並把其他不需要的連線資訊刪除(如下:username, password, host, database)。
const config = {
production: {
- username: "root",
- password: null,
- database: "database_test",
- host: "127.0.0.1",
dialect: "mysql",
+ use_env_variable: "CLEARDB_DATABASE_URL",
},
}
module.exports = config;
以使用者註冊為例,註冊成功,會成功在 database 建立一筆新資料,其中 id 為 PK,但為什麼 id 都是以十的倍數起跳呢?如: 11, 21, 31, 41?
後來參考了這篇 MySQL autoincrement column jumps by 10- why?
sequelize-cli db:migrate
?Heroku 使用 clearDB 建立了資料庫,但是有沒有指令可以把之前在 local 的建好的 database table 移到 Heroku 上呢?ㄈ
在 Heroku 上 run sequelize 建立 Table 的指令。
$ heroku run npx sequelize-cli db:migrate
另外,可以在部署好時,在 package.json 寫指令,使用 sequelize-cli 指令建立:
// package.json
{
"scripts": {
+ "db:migrate": "npx sequelize-cli db:migrate",
+ "start": "npm run db:migrate && node index.js"
- "start": "node index.js"
},
}
]]>修改 .gitignore
檔案時,把 /node_modules
寫錯了,所以要 git push heroku
時,連同 /node_modules
也 push 上 Heroku 了。
$ heroku logs --tail
...(略)
2022-05-22T23:09:40.062420+00:00 app[web.1]: Error: /app/node_modules/bcrypt/lib/binding/bcrypt_lib.node: invalid ELF header
參考此篇bcrypt error when deploy on Heroku : invalid ELF header #595,發現可以由以下方法補救:
.gitignore
上寫上應該被 git 忽略的檔案// google .gitignore 的 template,並加以修改:
/node_modules
.env
...
$ git rm -r --cached .
$ git add .
$ git commit -m "fixed untracked files"
$ git push heroku
ERR_INVALID_ARG_TYPE(name, 'string', value);
heroku logs --tail
heroku express deployinternal/validators.js:124 throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
#### 2.2 問題修改./models/index.js
裡面有引用 process.env[var_name]
但沒有引入 dotenv
library,所以發生了問題,因此在此檔案內加:require("dotenv").config();
console.log(process.env[var_name]
,Heroku 仍沒有吃到 .env
的變數在檔案內印了 process.env
的變數,但 Heroku 在執行時,沒有印出來,應該是沒有吃到 .env 變數。
// console.log('process.env.JWT_EXPIRES_IN', process.env.JWT_EXPIRES_IN)
// console.log('process.env.JWT_SECRET', process.env.JWT_SECRET)
$ heroku logs --tail
2022-05-22T05:56:18.729657+00:00 app[web.1]: Error: secretOrPrivateKey must have a value
2022-05-22T05:56:18.729657+00:00 app[web.1]: process.env.JWT_EXPIRES_IN
process.env.JWT_SECRET
參考此篇 StackOverflow How to set environment variables on Heroku for Node app and connect to the PostgreSQL database?,我發現可以使用 CLI 來設定 config。
$ heroku config // 查詢 Heroku 有哪些環境變數
polar-tor-55391 Config Vars
CLEARDB_DATABASE_URL: mysql://<host>:<pwd>@<host>/<dataBase>?reconnect=true
$ heroku config:set DB_HOST=my_DB // 設定新的環境參數名稱及內容
這個方法可以直接輸入環境變數名稱及內容,與上述使用 CLI 建立的方法是一樣的。
一開始出現了跟資料庫連現有關的問題:
$ heroku logs --tail
2022-05-22T06:22:42.386671+00:00 app[web.1]: Ignoring invalid configuration option passed to Connection: reconnect. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection
在 Heroku 上部署,環境應是 production
,此時打開 ./config/config.js
:
因為我已經在 Heroku 上建立 ClearDB MySQL 了,Heroku 資料庫連線的基本資訊(username, password, host, database)都已經附在 Heroku > settings > Config Vars
內,所以只要加 use_env_variable: "CLEARDB_DATABASE_URL",
這行,並把其他不需要的連線資訊刪除(如下:username, password, host, database)。
const config = {
production: {
- username: "root",
- password: null,
- database: "database_test",
- host: "127.0.0.1",
dialect: "mysql",
+ use_env_variable: "CLEARDB_DATABASE_URL",
},
}
module.exports = config;
以使用者註冊為例,註冊成功,會成功在 database 建立一筆新資料,其中 id 為 PK,但為什麼 id 都是以十的倍數起跳呢?如: 11, 21, 31, 41?
後來參考了這篇 MySQL autoincrement column jumps by 10- why?
sequelize-cli db:migrate
?Heroku 使用 clearDB 建立了資料庫,但是有沒有指令可以把之前在 local 的建好的 database table 移到 Heroku 上呢?ㄈ
在 Heroku 上 run sequelize 建立 Table 的指令。
$ heroku run npx sequelize-cli db:migrate
另外,可以在部署好時,在 package.json 寫指令,使用 sequelize-cli 指令建立:
// package.json
{
"scripts": {
+ "db:migrate": "npx sequelize-cli db:migrate",
+ "start": "npm run db:migrate && node index.js"
- "start": "node index.js"
},
}
]]>
// 專案資料夾結構
|- blog/ // 放置 blog 作品的資料夾
|- board/ // 放置 board 作品的資料夾
|- src_demo/ // 放置 README.md demo 的 gif / 圖片
|- README.md
git status
狀態branch:
- main (default)
- blog
距離上一次的 commit 為 10/29,然後在 main 主分支上,又有尚未被追蹤的檔案—— blog,
$ git log
commit 877115c3e8f6d0bf733565959fd19c8c66862f41
Author: estella00911 <estella00911@gmail.com>
Date: Fri Oct 29 16:19:34 2021 +0800
updage base url for single article page
$ git status
位於分支 main
未追蹤的檔案:
(使用 "git add <檔案>..." 以包含要提交的內容)
blog/
$ git log
commit ef5917f80ecf3c83a7bc330367ec3132f78a4c46
Author: estella00911 <estella00911@gmail.com>
Date: Tue Nov 2 23:16:04 2021 +0800
update css in nav and complete pagination 1st ver.
$ git status
位於分支 blog
沒有要提交的檔案,工作區為乾淨狀態
"Can’t automatically merge. Don’t worry, you can still create the pull request."
參考 GitHub "can't automatically merge"? 這篇的以下方法
git checkout master
git pull
git checkout your-branch
git merge master
然後在 local 端會列出發生衝突的檔案,點進去檔案觀看,會發現檔案內容,會把 current branch 及 main 不同之處使用以下標示:
>>>> current
======
<<<< HEAD
此時將需要的內容留下,重複的地方刪除,並刪除提示( >>>>>
、=====
、<<<<
)
再進行一次 git add、commit、push
就可以了!
// 專案資料夾結構
|- blog/ // 放置 blog 作品的資料夾
|- board/ // 放置 board 作品的資料夾
|- src_demo/ // 放置 README.md demo 的 gif / 圖片
|- README.md
git status
狀態branch:
- main (default)
- blog
距離上一次的 commit 為 10/29,然後在 main 主分支上,又有尚未被追蹤的檔案—— blog,
$ git log
commit 877115c3e8f6d0bf733565959fd19c8c66862f41
Author: estella00911 <estella00911@gmail.com>
Date: Fri Oct 29 16:19:34 2021 +0800
updage base url for single article page
$ git status
位於分支 main
未追蹤的檔案:
(使用 "git add <檔案>..." 以包含要提交的內容)
blog/
$ git log
commit ef5917f80ecf3c83a7bc330367ec3132f78a4c46
Author: estella00911 <estella00911@gmail.com>
Date: Tue Nov 2 23:16:04 2021 +0800
update css in nav and complete pagination 1st ver.
$ git status
位於分支 blog
沒有要提交的檔案,工作區為乾淨狀態
"Can’t automatically merge. Don’t worry, you can still create the pull request."
參考 GitHub "can't automatically merge"? 這篇的以下方法
git checkout master
git pull
git checkout your-branch
git merge master
然後在 local 端會列出發生衝突的檔案,點進去檔案觀看,會發現檔案內容,會把 current branch 及 main 不同之處使用以下標示:
>>>> current
======
<<<< HEAD
此時將需要的內容留下,重複的地方刪除,並刪除提示( >>>>>
、=====
、<<<<
)
再進行一次 git add、commit、push
就可以了!
GitHub 從 2021 年 8 月 13 日開始,不再支援密碼驗證 Git 的使用,改使用 private
token-base authentication
。
GitHub 沒有了密碼驗證,那 Git 要怎麼遠端連結 GitHub 的 repository 呢?就要先創建一個可以連到 GitHub Repository 的 access token。
點選「Generate new token」。
可以填寫 token 的說明,並設置完成後,點選「Generate token」。
這邊只會出現一次 token,等等要用在登入,先點選紅框將其複製下來。
$ git remote set-url origin https://<access_token>@github.com/<UserName>/<repository>.git
<access_token>
:剛剛 generate new token
<UserName>
:GitHub 使用者名稱
<repository>
:GitHub Repository 的名稱
按照上面類似的指令輸入,但最後面少輸入了 .git
,然後就發現無法連上(fatal),因此使用 git remote -v
來查詢一下, remote URL 是什麼,因為發現連不上,所以後來又使用 git remove -d <name>
刪除掉這個失敗的 remote URL。
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: 'https://github.com/Lidemy/mentor-program-5th-estella00911.git/' 身份驗證失敗
Jean-Lu-2:hw1 jeanlu$ git remote set-url origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911
Jean-Lu-2:hw1 jeanlu$ git remote-v
git:'remote-v' 不是一個 git 指令。參見 'git --help'。
最類似的指令有
remote-fd
Jean-Lu-2:hw1 jeanlu$ git remote -v
origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911 (fetch)
origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911 (push)
Jean-Lu-2:hw1 jeanlu$ git push origin week17
fatal: 無法存取 'https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911/':Could not resolve host: ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7
Jean-Lu-2:hw1 jeanlu$ git remote remove origin # 刪除失敗的 remote URL
Jean-Lu-2:hw1 jeanlu$ git remote -v # 檢查有沒有 remote URl 內容,發現沒有任何 remote URL。
Jean-Lu-2:hw1 jeanlu$ git remote add origin https://github.com/Lidemy/mentor-program-5th-estella00911.git # 加入 remote URL,並在 git 命名為 origin。
Jean-Lu-2:hw1 jeanlu$ git remote -v # 加入後,檢查 remote URL 。
origin https://github.com/Lidemy/mentor-program-5th-estella00911.git (fetch)
origin https://github.com/Lidemy/mentor-program-5th-estella00911.git (push)
Jean-Lu-2:hw1 jeanlu$ git push origin week17 # 欲 push 到 origin 的分支 week 17
Username for 'https://github.com': estella00911 # 填寫 username
Password for 'https://estella00911@github.com': # 將剛剛複製的那串 token 貼上。
# 成功 push 上去 GitHub
枚舉物件: 107, 完成.
物件計數中: 100% (107/107), 完成.
使用 4 個執行緒進行壓縮
壓縮物件中: 100% (92/92), 完成.
寫入物件中: 100% (95/95), 1.92 MiB | 2.45 MiB/s, 完成.
總共 95 (差異 25),復用 0 (差異 0),重用包 0
remote: Resolving deltas: 100% (25/25), completed with 8 local objects.
remote:
remote: Create a pull request for 'week17' on GitHub by visiting:
remote: https://github.com/Lidemy/mentor-program-5th-estella00911/pull/new/week17
remote:
To https://github.com/Lidemy/mentor-program-5th-estella00911.git
* [new branch] week17 -> week17
參考:
GitHub support for password authentication was removed
When try to pull or push in GitHub I am getting an error message: “Please use a personal access token instead.”- stackoverflow
Support for password authentication was removed. Please use a personal access token instead
GitHub 從 2021 年 8 月 13 日開始,不再支援密碼驗證 Git 的使用,改使用 private
token-base authentication
。
GitHub 沒有了密碼驗證,那 Git 要怎麼遠端連結 GitHub 的 repository 呢?就要先創建一個可以連到 GitHub Repository 的 access token。
點選「Generate new token」。
可以填寫 token 的說明,並設置完成後,點選「Generate token」。
這邊只會出現一次 token,等等要用在登入,先點選紅框將其複製下來。
$ git remote set-url origin https://<access_token>@github.com/<UserName>/<repository>.git
<access_token>
:剛剛 generate new token
<UserName>
:GitHub 使用者名稱
<repository>
:GitHub Repository 的名稱
按照上面類似的指令輸入,但最後面少輸入了 .git
,然後就發現無法連上(fatal),因此使用 git remote -v
來查詢一下, remote URL 是什麼,因為發現連不上,所以後來又使用 git remove -d <name>
刪除掉這個失敗的 remote URL。
remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.
remote: Please see https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information.
fatal: 'https://github.com/Lidemy/mentor-program-5th-estella00911.git/' 身份驗證失敗
Jean-Lu-2:hw1 jeanlu$ git remote set-url origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911
Jean-Lu-2:hw1 jeanlu$ git remote-v
git:'remote-v' 不是一個 git 指令。參見 'git --help'。
最類似的指令有
remote-fd
Jean-Lu-2:hw1 jeanlu$ git remote -v
origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911 (fetch)
origin https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911 (push)
Jean-Lu-2:hw1 jeanlu$ git push origin week17
fatal: 無法存取 'https://ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7/estella00911/mentor-program-5th-estella00911/':Could not resolve host: ghpxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFjL7
Jean-Lu-2:hw1 jeanlu$ git remote remove origin # 刪除失敗的 remote URL
Jean-Lu-2:hw1 jeanlu$ git remote -v # 檢查有沒有 remote URl 內容,發現沒有任何 remote URL。
Jean-Lu-2:hw1 jeanlu$ git remote add origin https://github.com/Lidemy/mentor-program-5th-estella00911.git # 加入 remote URL,並在 git 命名為 origin。
Jean-Lu-2:hw1 jeanlu$ git remote -v # 加入後,檢查 remote URL 。
origin https://github.com/Lidemy/mentor-program-5th-estella00911.git (fetch)
origin https://github.com/Lidemy/mentor-program-5th-estella00911.git (push)
Jean-Lu-2:hw1 jeanlu$ git push origin week17 # 欲 push 到 origin 的分支 week 17
Username for 'https://github.com': estella00911 # 填寫 username
Password for 'https://estella00911@github.com': # 將剛剛複製的那串 token 貼上。
# 成功 push 上去 GitHub
枚舉物件: 107, 完成.
物件計數中: 100% (107/107), 完成.
使用 4 個執行緒進行壓縮
壓縮物件中: 100% (92/92), 完成.
寫入物件中: 100% (95/95), 1.92 MiB | 2.45 MiB/s, 完成.
總共 95 (差異 25),復用 0 (差異 0),重用包 0
remote: Resolving deltas: 100% (25/25), completed with 8 local objects.
remote:
remote: Create a pull request for 'week17' on GitHub by visiting:
remote: https://github.com/Lidemy/mentor-program-5th-estella00911/pull/new/week17
remote:
To https://github.com/Lidemy/mentor-program-5th-estella00911.git
* [new branch] week17 -> week17
參考:
GitHub support for password authentication was removed
When try to pull or push in GitHub I am getting an error message: “Please use a personal access token instead.”- stackoverflow
Support for password authentication was removed. Please use a personal access token instead
路由:
|-- project
|-- index.js
|-- .env
|-- .sequelizerc
|-- config
|-- config.json -> config.js:require 引用 dotenv(在下載 sequelize-cli npm 自動產生)
|-- migrations
|-- seeders
|-- models
|-- index.js:修改 .json -> .js
|-- views
|-- public
- 安裝 dotenv
- 在專案根目錄新增
.env
檔案,新增環境變數- 在
/project/config/config.json
修改檔案類型與其檔案內容- 在專案根目錄(
/project
)新增.sequelizerc
檔案,修改config 的檔案類型
。- 在
/project/models/index.js
修改檔案內的文字。- 將
session secret key
放到環境變數。- 測試一下,有沒有出問題。
- 重要在
.gitignore
忽略.env
檔案
在專案資料夾的根目錄下 terminal 安裝
npm install --save--dev dotenv
+ dotenv@10.0.0
added 1 package and audited 795 packages in 5.517s
67 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
╭────────────────────────────────────────────────────────────────╮
│ │
│ New major version of npm available! 6.14.12 → 7.20.6 │
│ Changelog: https://github.com/npm/cli/releases/tag/v7.20.6 │
│ Run npm install -g npm to update! │
│ │
╰────────────────────────────────────────────────────────────────╯
npm dotenv --version
$ npm dotenv --version
6.14.12
.env
檔案,新增環境變數.env
檔案$ pwd
/project
$ touch .env
# 建立好 .env 檔案後,開啟 .env 編輯
.env
檔案,新增環境變數可以將敏感資訊,例如 database 的連結資訊放入 .env
檔案內:
新增並分別令與database 有關的變數為 DB_HOST
、DB_USERNAME
、DB_PASSWORD
、DB_PORT
、DB_DATABASE
。
// /project/.env
DB_HOST=localhost
DB_USERNAME=user01
DB_PASSWORD=password01
DB_PORT=8080
DB_DATABASE=testdb
SESSION_SECRET: xxxx
/project/config/config.json
修改檔案類型與其檔案內容// 檔名:config.json
{
"development": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
修改以下行首為加號的地方,並將檔名更為 config.js
// 修改檔名:從 config.json → config.js
+ require('dotenv').config();
+ const config = {
{
"development": {
+ "username": process.env.DB_USERNAME,
+ "password": process.env.DB_PASSWORD,
+ "database": process.env.DB_DATABASE,
+ "host": process.env.DB_HOST,
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
+ module.exports = config;
小結:
config.js
接下來將檔名更改了,那這樣 sequelize-cli 怎麼找的到 config 檔案,來連結資料庫呢?
就要在以下步驟新增 .sequelizerc
來調整路徑。
/project
)新增 .sequelizerc
檔案,修改 config 的檔案類型
。 'use strict';
require('dotenv').config(); // don't forget to require dotenv
const path = require('path');
module.exports = {
+ // 原本是 config.json,修改成 config.js
+ 'config': path.resolve('config', 'config.js'),
- 'config': path.resolve('config', 'config.json'),
'models-path': path.resolve('models'),
'seeders-path': path.resolve('seeders'),
'migrations-path': path.resolve('migrations'),
};
/project/models/index.js
修改檔案內的文字。原先沒有修改這個檔案的內容,結果發現出現以下錯誤:
PS:路徑可以將 /Users/jeanlu/document/github/mentor-program-5th-estella00911/homeworks/week17/hw1/models
看成 /project/models
即可。
Error: Cannot find module 'xxx/project/models/config/config.json'
Require stack:
- xxx/project/models/index.js
- xxx/project/controllers/user.js
- xxx/project/index.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (xxx/project/models/index.js:8:16)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'xxx/project/models/index.js',
'xxx/project/controllers/user.js',
'xxx/project/index.js'
]
}
發現居然跟 /models/index.js
有關,於是查了相關的,發現 config
的路徑不對,就將原本的 const config = require(__dirname + '/../config/config.json')[env];
改成 const config = require(__dirname + '/../config/config.js')[env];
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
+ const config = require(__dirname + '/../config/config.js')[env];
- const config = require(__dirname + '/../config/config.json')[env];
const db = {};
再執行一次,就 OK 了!
session secret key
放到環境變數。在 app.js/ index.js 中,要將 session
的 secret key
放到環境變數,並從環境變數中引用:
+ // project/index.js
+ require('dotenv').config(); // 引用 dotenv npm module
const express = require('express')
const path = require('path')
const bodyParser = require('body-parser');
const flash = require('connect-flash')
const session = require('express-session')
const moment = require('moment');
const shortDateFormat = 'YYYY-MM-DD HH:mm'; //"ddd @ h:mmA"
const app = express();
const port = process.env.DB_PORT
const userController = require('./controllers/user')
const blogController = require('./controllers/blog')
app.set('views', './views')
app.set('view engine', 'ejs')
app.use('/public', express.static(__dirname + '/public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(flash())
app.use(session({
- secret: 'xxxxxxxxx' // 原本的 secret key 是放在 index.js 檔案內的,但這樣是不安全,需要像下面這行一樣,存在環境變數!
+ secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
# 略
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
$ node index.js
body-parser deprecated undefined extended: provide extended option index.js:21:20
Example app listening at http://localhost:xxxx
.gitignore
忽略 .env
檔案將敏感資料設置在環境變數裡面,就是不要讓別人知道這些具有隱私的資料,所以當然不能把這些隱私的資料上傳到 GitHub 呀!所以在 push 上 GitHub 之前,要先設定將這個檔案 ignore 掉!
這時候要先移動到根目錄:
$ pwd
xxx/project/
$ ls -al
drwxr-xr-x 14 jeanlu staff 448 8 20 12:05 .
drwxr-xr-x 7 jeanlu staff 224 8 14 13:50 ..
-rw-r--r--@ 1 jeanlu staff 10244 8 19 09:08 .DS_Store
-rw-r--r-- 1 jeanlu staff 121 8 20 11:52 .env
-rw-r--r-- 1 jeanlu staff 314 8 19 18:41 .sequelizerc
drwxr-xr-x 3 jeanlu staff 96 8 20 09:34 config
drwxr-xr-x 4 jeanlu staff 128 8 13 17:48 controllers
-rw-r--r--@ 1 jeanlu staff 2071 8 20 12:16 index.js
drwxr-xr-x 5 jeanlu staff 160 8 16 19:33 migrations
drwxr-xr-x 6 jeanlu staff 192 8 16 19:33 models
drwxr-xr-x 5 jeanlu staff 160 8 19 09:10 public
drwxr-xr-x 3 jeanlu staff 96 8 17 14:59 scripts
drwxr-xr-x 2 jeanlu staff 64 8 15 13:59 seeders
drwxr-xr-x 12 jeanlu staff 384 8 17 18:12 views
-rw-r--r-- 1 jeanlu staff 6261697 7 19 00:24 .eslintcache
-rw-r--r-- 1 jeanlu staff 70 7 26 21:15 .eslintignore
-rw-r--r-- 1 jeanlu staff 348 4 26 14:06 .eslintrc.js
drwxr-xr-x 15 jeanlu staff 480 8 19 18:42 .git
-rw-r--r-- 1 jeanlu staff 51 8 19 18:29 .gitignore
drwxr-xr-x 5 jeanlu staff 160 4 26 14:08 .husky
-rw-r--r-- 1 jeanlu staff 55234 4 26 14:06 README.md
drwxr-xr-x 518 jeanlu staff 16576 8 19 18:20 node_modules
-rw-r--r-- 1 jeanlu staff 278808 8 19 18:20 package-lock.json
-rw-r--r-- 1 jeanlu staff 1355 8 19 18:20 package.json
$ vim .gitignore
使用 vim 編輯器,打開 .gitignore
,加上 .env
,這樣在 push 至 GitHub 時,就不會 push 到具有敏感資料的 .env
。
node_modules/
conn.php
.DS_STORE
.eslintcache
+ .env
參考:
dotenv - npm
Sequelize Migrate Not Recognising Dotenv - stackoverflow
Importance of session secret key in Express web framework - semicolonworld
路由:
|-- project
|-- index.js
|-- .env
|-- .sequelizerc
|-- config
|-- config.json -> config.js:require 引用 dotenv(在下載 sequelize-cli npm 自動產生)
|-- migrations
|-- seeders
|-- models
|-- index.js:修改 .json -> .js
|-- views
|-- public
- 安裝 dotenv
- 在專案根目錄新增
.env
檔案,新增環境變數- 在
/project/config/config.json
修改檔案類型與其檔案內容- 在專案根目錄(
/project
)新增.sequelizerc
檔案,修改config 的檔案類型
。- 在
/project/models/index.js
修改檔案內的文字。- 將
session secret key
放到環境變數。- 測試一下,有沒有出問題。
- 重要在
.gitignore
忽略.env
檔案
在專案資料夾的根目錄下 terminal 安裝
npm install --save--dev dotenv
+ dotenv@10.0.0
added 1 package and audited 795 packages in 5.517s
67 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
╭────────────────────────────────────────────────────────────────╮
│ │
│ New major version of npm available! 6.14.12 → 7.20.6 │
│ Changelog: https://github.com/npm/cli/releases/tag/v7.20.6 │
│ Run npm install -g npm to update! │
│ │
╰────────────────────────────────────────────────────────────────╯
npm dotenv --version
$ npm dotenv --version
6.14.12
.env
檔案,新增環境變數.env
檔案$ pwd
/project
$ touch .env
# 建立好 .env 檔案後,開啟 .env 編輯
.env
檔案,新增環境變數可以將敏感資訊,例如 database 的連結資訊放入 .env
檔案內:
新增並分別令與database 有關的變數為 DB_HOST
、DB_USERNAME
、DB_PASSWORD
、DB_PORT
、DB_DATABASE
。
// /project/.env
DB_HOST=localhost
DB_USERNAME=user01
DB_PASSWORD=password01
DB_PORT=8080
DB_DATABASE=testdb
SESSION_SECRET: xxxx
/project/config/config.json
修改檔案類型與其檔案內容// 檔名:config.json
{
"development": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
修改以下行首為加號的地方,並將檔名更為 config.js
// 修改檔名:從 config.json → config.js
+ require('dotenv').config();
+ const config = {
{
"development": {
+ "username": process.env.DB_USERNAME,
+ "password": process.env.DB_PASSWORD,
+ "database": process.env.DB_DATABASE,
+ "host": process.env.DB_HOST,
"dialect": "mysql"
},
"test": {
"username": "root",
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": null,
"database": "database_production",
"host": "127.0.0.1",
"dialect": "mysql"
}
}
+ module.exports = config;
小結:
config.js
接下來將檔名更改了,那這樣 sequelize-cli 怎麼找的到 config 檔案,來連結資料庫呢?
就要在以下步驟新增 .sequelizerc
來調整路徑。
/project
)新增 .sequelizerc
檔案,修改 config 的檔案類型
。 'use strict';
require('dotenv').config(); // don't forget to require dotenv
const path = require('path');
module.exports = {
+ // 原本是 config.json,修改成 config.js
+ 'config': path.resolve('config', 'config.js'),
- 'config': path.resolve('config', 'config.json'),
'models-path': path.resolve('models'),
'seeders-path': path.resolve('seeders'),
'migrations-path': path.resolve('migrations'),
};
/project/models/index.js
修改檔案內的文字。原先沒有修改這個檔案的內容,結果發現出現以下錯誤:
PS:路徑可以將 /Users/jeanlu/document/github/mentor-program-5th-estella00911/homeworks/week17/hw1/models
看成 /project/models
即可。
Error: Cannot find module 'xxx/project/models/config/config.json'
Require stack:
- xxx/project/models/index.js
- xxx/project/controllers/user.js
- xxx/project/index.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:880:15)
at Function.Module._load (internal/modules/cjs/loader.js:725:27)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.<anonymous> (xxx/project/models/index.js:8:16)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'xxx/project/models/index.js',
'xxx/project/controllers/user.js',
'xxx/project/index.js'
]
}
發現居然跟 /models/index.js
有關,於是查了相關的,發現 config
的路徑不對,就將原本的 const config = require(__dirname + '/../config/config.json')[env];
改成 const config = require(__dirname + '/../config/config.js')[env];
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
+ const config = require(__dirname + '/../config/config.js')[env];
- const config = require(__dirname + '/../config/config.json')[env];
const db = {};
再執行一次,就 OK 了!
session secret key
放到環境變數。在 app.js/ index.js 中,要將 session
的 secret key
放到環境變數,並從環境變數中引用:
+ // project/index.js
+ require('dotenv').config(); // 引用 dotenv npm module
const express = require('express')
const path = require('path')
const bodyParser = require('body-parser');
const flash = require('connect-flash')
const session = require('express-session')
const moment = require('moment');
const shortDateFormat = 'YYYY-MM-DD HH:mm'; //"ddd @ h:mmA"
const app = express();
const port = process.env.DB_PORT
const userController = require('./controllers/user')
const blogController = require('./controllers/blog')
app.set('views', './views')
app.set('view engine', 'ejs')
app.use('/public', express.static(__dirname + '/public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(flash())
app.use(session({
- secret: 'xxxxxxxxx' // 原本的 secret key 是放在 index.js 檔案內的,但這樣是不安全,需要像下面這行一樣,存在環境變數!
+ secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
# 略
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
$ node index.js
body-parser deprecated undefined extended: provide extended option index.js:21:20
Example app listening at http://localhost:xxxx
.gitignore
忽略 .env
檔案將敏感資料設置在環境變數裡面,就是不要讓別人知道這些具有隱私的資料,所以當然不能把這些隱私的資料上傳到 GitHub 呀!所以在 push 上 GitHub 之前,要先設定將這個檔案 ignore 掉!
這時候要先移動到根目錄:
$ pwd
xxx/project/
$ ls -al
drwxr-xr-x 14 jeanlu staff 448 8 20 12:05 .
drwxr-xr-x 7 jeanlu staff 224 8 14 13:50 ..
-rw-r--r--@ 1 jeanlu staff 10244 8 19 09:08 .DS_Store
-rw-r--r-- 1 jeanlu staff 121 8 20 11:52 .env
-rw-r--r-- 1 jeanlu staff 314 8 19 18:41 .sequelizerc
drwxr-xr-x 3 jeanlu staff 96 8 20 09:34 config
drwxr-xr-x 4 jeanlu staff 128 8 13 17:48 controllers
-rw-r--r--@ 1 jeanlu staff 2071 8 20 12:16 index.js
drwxr-xr-x 5 jeanlu staff 160 8 16 19:33 migrations
drwxr-xr-x 6 jeanlu staff 192 8 16 19:33 models
drwxr-xr-x 5 jeanlu staff 160 8 19 09:10 public
drwxr-xr-x 3 jeanlu staff 96 8 17 14:59 scripts
drwxr-xr-x 2 jeanlu staff 64 8 15 13:59 seeders
drwxr-xr-x 12 jeanlu staff 384 8 17 18:12 views
-rw-r--r-- 1 jeanlu staff 6261697 7 19 00:24 .eslintcache
-rw-r--r-- 1 jeanlu staff 70 7 26 21:15 .eslintignore
-rw-r--r-- 1 jeanlu staff 348 4 26 14:06 .eslintrc.js
drwxr-xr-x 15 jeanlu staff 480 8 19 18:42 .git
-rw-r--r-- 1 jeanlu staff 51 8 19 18:29 .gitignore
drwxr-xr-x 5 jeanlu staff 160 4 26 14:08 .husky
-rw-r--r-- 1 jeanlu staff 55234 4 26 14:06 README.md
drwxr-xr-x 518 jeanlu staff 16576 8 19 18:20 node_modules
-rw-r--r-- 1 jeanlu staff 278808 8 19 18:20 package-lock.json
-rw-r--r-- 1 jeanlu staff 1355 8 19 18:20 package.json
$ vim .gitignore
使用 vim 編輯器,打開 .gitignore
,加上 .env
,這樣在 push 至 GitHub 時,就不會 push 到具有敏感資料的 .env
。
node_modules/
conn.php
.DS_STORE
.eslintcache
+ .env
參考:
dotenv - npm
Sequelize Migrate Not Recognising Dotenv - stackoverflow
Importance of session secret key in Express web framework - semicolonworld
每次只要 PHP 有任何錯誤,小錯誤例如少了分號,或者是大錯誤,如邏輯不對、找不到變數等等。都只有顯示空白,需要自己一行一行去 debug,因為是正在學習模仿的階段,可以對照著別人的 code 比對,但是這長久也不是辦法,所以著手 Google 到底是發生了什麼事情?
display_errors
開關的差別:錯誤版本的 php 檔,少了;
:
<?php
// ...略
$username = $user['username']
// ...略
?>
印出結果為: error 500,沒有 load 出來錯在哪:
Parse error: syntax error, unexpected token "}" in /Applications/XAMPP/xamppfiles/htdocs/be101/board_mine/index.php on line 14
錯誤版本的 php 檔,錯誤之處在於少了;
:
<?php
// ...略
$username = $user['username']
// ...略
?>
印出結果為: error 500,沒有 load 出來錯在哪:
php.ini
就對了!執行php網頁出現【這個網頁無法正常運作】的解決方法
萬事都有個但是!每個 windows 都告訴我 php.ini 的檔案路徑在哪,但我是 Mac 就是找不到他的路徑在哪,崩潰!
直到我找到這一個教學影片Setting display_errors variable in the php.ini for XAMPP on Macintosh,影片中教我怎麼找到 php.ini
,還教我怎麼樣開啟 display_errors: on
,真的是在茫茫的雲裡、霧裡看到新世界!
php.ini
到底位在 Mac XAMPP 的哪裡呢?php.ini
,這樣就可以找到 php.ini
存在 XAMPP 資料夾的位置。php.ini
位在Configuration File (php.ini) Path/Applications/XAMPP/xamppfiles/etc
display_errors
的開關囉!display_errors
後,將 Off
改為 On
,並存檔。display_errors
改為 on。當我 PHP 檔案有誤,然後執行時,就可以看到跟別人一樣的錯誤訊息提示頁面囉!如下:
每次只要 PHP 有任何錯誤,小錯誤例如少了分號,或者是大錯誤,如邏輯不對、找不到變數等等。都只有顯示空白,需要自己一行一行去 debug,因為是正在學習模仿的階段,可以對照著別人的 code 比對,但是這長久也不是辦法,所以著手 Google 到底是發生了什麼事情?
display_errors
開關的差別:錯誤版本的 php 檔,少了;
:
<?php
// ...略
$username = $user['username']
// ...略
?>
印出結果為: error 500,沒有 load 出來錯在哪:
Parse error: syntax error, unexpected token "}" in /Applications/XAMPP/xamppfiles/htdocs/be101/board_mine/index.php on line 14
錯誤版本的 php 檔,錯誤之處在於少了;
:
<?php
// ...略
$username = $user['username']
// ...略
?>
印出結果為: error 500,沒有 load 出來錯在哪:
php.ini
就對了!執行php網頁出現【這個網頁無法正常運作】的解決方法
萬事都有個但是!每個 windows 都告訴我 php.ini 的檔案路徑在哪,但我是 Mac 就是找不到他的路徑在哪,崩潰!
直到我找到這一個教學影片Setting display_errors variable in the php.ini for XAMPP on Macintosh,影片中教我怎麼找到 php.ini
,還教我怎麼樣開啟 display_errors: on
,真的是在茫茫的雲裡、霧裡看到新世界!
php.ini
到底位在 Mac XAMPP 的哪裡呢?php.ini
,這樣就可以找到 php.ini
存在 XAMPP 資料夾的位置。php.ini
位在Configuration File (php.ini) Path/Applications/XAMPP/xamppfiles/etc
display_errors
的開關囉!display_errors
後,將 Off
改為 On
,並存檔。display_errors
改為 on。當我 PHP 檔案有誤,然後執行時,就可以看到跟別人一樣的錯誤訊息提示頁面囉!如下:
先前想要解決 PHP 檔案內的程式碼出錯時,render 在瀏覽器上,就會出現 Error 500 的問題,所以就將 XAMPP 解除安裝,後來又重新安裝 XAMPP。有備份存放 php 檔案的路徑:application > XAMPP > htdocs > be101 > xxx.php
,只解除安裝了 XAMPP 本身(但我後來查資料說需要把資料庫跟 php 檔案備份,我忘了做資料庫備份這個動作,我猜想是這個發生了悲劇)。
但是再次打開 XAMPP 連上 MySQL database、Apache 後,打開 phpMyAdmin 資料庫發現無法讀取我想要的資料表,所以想要砍掉重練,再新建一個資料表,寫入欄位,結果在 phpMyAdmin 刪除資料表(data table)時,發生三個問題:
Column count of mysql.proc is wrong. Expected 21, found 20. Created with MariaDB 100108, now running 100419. Please use mysql_upgrade to fix this error code example
Tablespace for table "jean.users' exists. Please DISCARD the tablespace before IMPORT.
因為之前誤刪了 XAMPP,趕緊從 downloads 找出上個月下載的 XAMPP.dmg 映像檔(8.0.6 / PHP 8.0.6),重新安裝。
Column count of mysql.proc is wrong. Expected 21, found 20. Created with MariaDB 100108, now running 100419. Please use mysql_upgrade to fix this error code example
先前安裝好 XAMPP 所做的舊資料表,但是在新安裝的 XAMPP 卻刪除不了,查詢網頁上的解決方法,但苦於 mac 沒辦法找 CLI 輸入更新的指令(如下)
mysql_upgrade -u root -p
service mysqld restart
所以就解除安裝 XAMPP,再去官網安裝一次最新版本的 XAMPP(8.0.7 / PHP 8.0.7)。
我覺得應該是重新安裝與解除安裝的步驟沒有做完整,查了一下資料,我發現我少備份一樣資料application > XAMPP > xamppfiles > var > mysql > ibdata1
如果沒有備份的話,重新安裝成功後,會無法打開原本的 mySQL 資料表。
另外解除安裝的話,需要使用 XAMPP 裡面附的 uninstall.app,位在 application > XAMPP > uninstall.app 內。
Tablespace for table "jean.users' exists. Please DISCARD the tablespace before IMPORT.
又是相同的困擾...我找了好久都沒看到 mac 版的 XAMPP 可以輸入指令,於是就在 XAMPP 資料夾循著 windows 的資料庫檔案路徑,找到了疑似存取資料庫的位置:application > xamppfiles > var > mysql > jean,然後說點選兩下 jean 資料夾,他說我沒有權限存取資料夾,然後我比照了一下 phpMyAdmin 資料庫的資料表列表,發現挺相似的,於是我就鼓起勇氣在 finder 按刪除,再翻回去 phpMyAdmin 看資料表列表,就發現 jean 這個資料表不見了,成功暴力刪除了資料表...
https://i.imgur.com/pKdfr3B.png
https://i.imgur.com/H7ww8lu.png
先前想要解決 PHP 檔案內的程式碼出錯時,render 在瀏覽器上,就會出現 Error 500 的問題,所以就將 XAMPP 解除安裝,後來又重新安裝 XAMPP。有備份存放 php 檔案的路徑:application > XAMPP > htdocs > be101 > xxx.php
,只解除安裝了 XAMPP 本身(但我後來查資料說需要把資料庫跟 php 檔案備份,我忘了做資料庫備份這個動作,我猜想是這個發生了悲劇)。
但是再次打開 XAMPP 連上 MySQL database、Apache 後,打開 phpMyAdmin 資料庫發現無法讀取我想要的資料表,所以想要砍掉重練,再新建一個資料表,寫入欄位,結果在 phpMyAdmin 刪除資料表(data table)時,發生三個問題:
Column count of mysql.proc is wrong. Expected 21, found 20. Created with MariaDB 100108, now running 100419. Please use mysql_upgrade to fix this error code example
Tablespace for table "jean.users' exists. Please DISCARD the tablespace before IMPORT.
因為之前誤刪了 XAMPP,趕緊從 downloads 找出上個月下載的 XAMPP.dmg 映像檔(8.0.6 / PHP 8.0.6),重新安裝。
Column count of mysql.proc is wrong. Expected 21, found 20. Created with MariaDB 100108, now running 100419. Please use mysql_upgrade to fix this error code example
先前安裝好 XAMPP 所做的舊資料表,但是在新安裝的 XAMPP 卻刪除不了,查詢網頁上的解決方法,但苦於 mac 沒辦法找 CLI 輸入更新的指令(如下)
mysql_upgrade -u root -p
service mysqld restart
所以就解除安裝 XAMPP,再去官網安裝一次最新版本的 XAMPP(8.0.7 / PHP 8.0.7)。
我覺得應該是重新安裝與解除安裝的步驟沒有做完整,查了一下資料,我發現我少備份一樣資料application > XAMPP > xamppfiles > var > mysql > ibdata1
如果沒有備份的話,重新安裝成功後,會無法打開原本的 mySQL 資料表。
另外解除安裝的話,需要使用 XAMPP 裡面附的 uninstall.app,位在 application > XAMPP > uninstall.app 內。
Tablespace for table "jean.users' exists. Please DISCARD the tablespace before IMPORT.
又是相同的困擾...我找了好久都沒看到 mac 版的 XAMPP 可以輸入指令,於是就在 XAMPP 資料夾循著 windows 的資料庫檔案路徑,找到了疑似存取資料庫的位置:application > xamppfiles > var > mysql > jean,然後說點選兩下 jean 資料夾,他說我沒有權限存取資料夾,然後我比照了一下 phpMyAdmin 資料庫的資料表列表,發現挺相似的,於是我就鼓起勇氣在 finder 按刪除,再翻回去 phpMyAdmin 看資料表列表,就發現 jean 這個資料表不見了,成功暴力刪除了資料表...
https://i.imgur.com/pKdfr3B.png
https://i.imgur.com/H7ww8lu.png
1. const request = require('request')
2.
3. url = 'https://lidemy-book-store.herokuapp.com/books' // 也可以設成API_ENDPOINT
4.
5. request( url, listTenBooks)
6.
7. function listTenBooks(error, response, body) {
8. /* request() 出錯:通常是發送的過程有問題,然後沒有接到任何回應。 */
9. if (error) {
10. console.log(`請求錯誤: ${error}`)
11. return
12. }
13.
14. // 程式碼先處理Status Code 的4xx 5xx,都順利
15. if (response.statusCode >=300) {
16. console.log(`請求錯誤,狀態碼:${response.statusCode}`)
17. return
18. }
19.
20. /* 處理 API Link 的資料:有沒有抓到 API 文件 */
21. let json = {};
22. try {
23. json = JSON.parse(body) // 把 json 格式的字串 -> JavaScript 的 object 形式
24. } catch (error) {
25. console.log('error!!! 資料解析錯誤')
26. console.log('ERROR:', error)
27. return
28. }
29.
30. /* 印出書目上有哪些書 */
31. for (let i = 0; i < 10; i++) {
32. console.log(json[i].id, json[i].name)
33. }
34. }
Ans.
request() 給出錯誤:通常是在發送的過程有問題,然後沒有接到任何回應。
Status Code 4xx 5xx 錯誤: request 有發送出去,然後 response 得到的 status code
問題描述:先前在 line 30 上列出 json.parse 轉換錯誤的問題:可能是 API 不符合 json 格式或者無法使用 API 文件內的資料,可能是沒有權限訪問該頁面或瀏覽器本版錯誤等問題
Ans.
通常都是列出 error,再個別自己去找 statusCode 顯示的問題。
舉例是 status code 4xx 5xx 有很多問題要處理,不用一一列出來,使用 console.log('ERROR!!:', response.statusCode)
即可
24. catch (error) {
console.log(' (2) 網址有效,但無法使用 API 文件內的資料,可能是沒有權限訪問該頁面或瀏覽器本版錯誤等問題')')}
Ans.
所以處理優先順序
(1) <line 15~17> statusCode 判讀 400 500, console.log(statuscode) 後 return 結束 function
(2) <line 22~28> json.parse 抓資料
1. const request = require('request')
2.
3. url = 'https://lidemy-book-store.herokuapp.com/books' // 也可以設成API_ENDPOINT
4.
5. request( url, listTenBooks)
6.
7. function listTenBooks(error, response, body) {
8. /* request() 出錯:通常是發送的過程有問題,然後沒有接到任何回應。 */
9. if (error) {
10. console.log(`請求錯誤: ${error}`)
11. return
12. }
13.
14. // 程式碼先處理Status Code 的4xx 5xx,都順利
15. if (response.statusCode >=300) {
16. console.log(`請求錯誤,狀態碼:${response.statusCode}`)
17. return
18. }
19.
20. /* 處理 API Link 的資料:有沒有抓到 API 文件 */
21. let json = {};
22. try {
23. json = JSON.parse(body) // 把 json 格式的字串 -> JavaScript 的 object 形式
24. } catch (error) {
25. console.log('error!!! 資料解析錯誤')
26. console.log('ERROR:', error)
27. return
28. }
29.
30. /* 印出書目上有哪些書 */
31. for (let i = 0; i < 10; i++) {
32. console.log(json[i].id, json[i].name)
33. }
34. }
Ans.
request() 給出錯誤:通常是在發送的過程有問題,然後沒有接到任何回應。
Status Code 4xx 5xx 錯誤: request 有發送出去,然後 response 得到的 status code
問題描述:先前在 line 30 上列出 json.parse 轉換錯誤的問題:可能是 API 不符合 json 格式或者無法使用 API 文件內的資料,可能是沒有權限訪問該頁面或瀏覽器本版錯誤等問題
Ans.
通常都是列出 error,再個別自己去找 statusCode 顯示的問題。
舉例是 status code 4xx 5xx 有很多問題要處理,不用一一列出來,使用 console.log('ERROR!!:', response.statusCode)
即可
24. catch (error) {
console.log(' (2) 網址有效,但無法使用 API 文件內的資料,可能是沒有權限訪問該頁面或瀏覽器本版錯誤等問題')')}
Ans.
所以處理優先順序
(1) <line 15~17> statusCode 判讀 400 500, console.log(statuscode) 後 return 結束 function
(2) <line 22~28> json.parse 抓資料
Q1: 要抓取 API 文件內的資料,需要用到 HTTP method 來達成,其中
request(url, function(error, response, body) => {...})
中的是什麼意思呢?
在解釋 response body 前,要先回顧一下網頁是怎麼打開的,還記得先前在 week 1 有提到過怎麼在瀏覽器打開網頁的過程嗎?在 Google 首頁搜尋框打上:JavaScript,並且按下 Enter後,會跟瀏覽器說送出 JavaScript 的 request,瀏覽器跟作業系統說送出 reqeust,作業系統跟網路說要送出 request 給 google 的 server,把資料送到 dataBase,google server 回傳 response 給網路,網路再把 response 交還給作業系統,之後作業系統把 response 給 chrome 瀏覽器,最後 google chrome 在顯示出結果。
其實在這個HTTP message 中分為「發送 request」 及 「接收 response」,裡面有規範固定的格式,讓大家可以依照 HTTP 規則傳達網路訊息,HTTP message 內的組成為 starter-line、HTTP headers、empty line、body。
1.starter-line:描述要用什麼方法實現 request,如POST
、GET
、PATCH
等,及 status code(如:200 OK)。
syntax: request method, request target, HTTP version
example: POST /?id=1 HTTP/1.1
HTTP/1.1 200 OK
2. HTTP headers:附加的重要資訊,如訂便當服務,要不要辣,何時外送抵達,要不要免洗餐具。在實際網路應用上,有標示哪一款瀏覽器(Chrome、IE、FireFox)、內容形式為 json、html等。在 request 中會出現幾類的 headers,有 general headers(如:via
)、request headers(如:User-Agent
或 Accept
)、formerly entity headers(如:content-length
),舉例的 headers 先有個印象即可。
現在瞭解 HTTP request 和 response 會傳送什麼樣的資料後,就可以來研究一下request(url, function(error, response, body) => {...})
。
舉一個餐廳點餐的例子:
用餐的客人向餐廳內的服務員點餐(發出 request):我要跟廚師點一客七分熟的腓力牛排,附蘑菇醬汁,然後服務員會回覆(response):成功點餐或此品項已售罄。
<客人的 request>
header:
牛排熟度:七分熟
醬汁:蘑菇醬
body:
腓力牛排
<服務員的 response>
200 OK
---------
成功點餐
<服務員的 response>
400 error
---------
此品項已賣光
一般人在點餐時,發出請求(request)會希望得到的回覆是有沒有錯誤(error)、答覆(response)、確切內容(body),就如請求 API 文件內的資料時一樣,輸入參數(parameter)在向 API 文件請求資料的時候,也會希望可以獲得 API 文件裡面的資料(body)、回覆(response)或者出錯時的 error 的資訊。
因為 request 只是一個動作的要求,具體要求什麼東西,做什麼事,需要另外寫清楚,例如:要求進去這個網頁,需要進去什麼網頁(目的地),進去網頁後要做什麼?以串接API文件為例子的話,就是發出 request 要使用這個 API 文件內的資訊,目的地就是該 API 文件的 URL,要做什麼的話,就是利用 function 包住要做的事情(將API文件內的資訊抓出來)。
透過串接 API 文件裡的資訊來實際演練 HTTP request 和 response,利用 Node.js 及 npm modules 的 request 循序漸進的練習。
client-id
、accept
、HTTP basic authorization
,以下為練習的例子:request.post
新增資料時,在 headers 裡加入content-type
,讓新增的資料符合格式。HTTP 基本認證
搭配學習。user-agent
來辨別瀏覽器。Q3: API 是什麼? RESTful API 又是什麼?
API 是什麼?
常常可以在 App Store 或者 Google Play 上看見氣象跟星象有關的 app,或者是在網誌上看食記的時候,會看到文章內鑲嵌 Google Map 地圖,網誌跟 app 的資訊都是來自 Google Map 跟氣象局的資料。在 Google Map 和氣象局的角度,就是提供資料,而在 app 和食記的角度,就是在使用資料,這樣一來一往就是交換資料,但是一般人不會想把自己的資料直接分享給別人使用,可能會有一些隱私顧慮,所以利用另一種形式將提供資料給大眾使用,這樣有利於大眾做一些新功能的開發,例如:使用他方的星象跟氣象資料,製作的新 app,或者是幫助食記圖像化餐廳位置的 Google Map。那這些資料種類繁多、資料龐大,怎麼樣讓大家可以擷取使用?就需要訂立一個統一化的格式、規範跟環境,讓大家不僅可以分享資料,也可以使用這些資料。 這些資料的提供跟使用,就是使用 API 這個方法,API 全名是應用程式介面(application programming interface),重點是「介面」這個詞,先前提到,若要讓大家都看的懂資料,就要有統一的格式跟環境,這個 API 就是中間的媒介,讓大家可以擷取跟提供資料,有了資料的統一格式跟資料說明,再搭配程式語言的輔助,讓大家可以成功的將資料交換,讓更多人可以使用資料跟開發新功能。
RESTful API
RESTful API 是基於設計風格所創造,對 data 的動作如:新增、修改、刪除、取得,剛剛好對應到 HTTP method 的 GET
、POST
、DELETE
、GET
。如果是 HTTP method 的話,要先瞭解每個指令的意義跟使用方式,而 RESTful API 將這些指令對應成白話的動作:新增、刪除、取得。
Q4: try{...} catch() {...} throw 要怎麼使用?為什麼需要?
有時候再執行 js 時,不知道哪裡出了錯,可以使用 try catch ,抓到某個錯誤時,會 console.log()出的資訊,來看哪裡發生。其實也可以用在預期錯誤,在執行發生錯誤時,提供錯誤修正的提示。
throw
是直接丟出訊息,可以這樣使用 throw 'Opps!!!'
,只要執行這一行,就會出現 'Opps!!!'
。
HTTP/1.1 — 訊息格式 (Message Format)
npm modules -- request
HTTP headers
Q1: 要抓取 API 文件內的資料,需要用到 HTTP method 來達成,其中
request(url, function(error, response, body) => {...})
中的是什麼意思呢?
在解釋 response body 前,要先回顧一下網頁是怎麼打開的,還記得先前在 week 1 有提到過怎麼在瀏覽器打開網頁的過程嗎?在 Google 首頁搜尋框打上:JavaScript,並且按下 Enter後,會跟瀏覽器說送出 JavaScript 的 request,瀏覽器跟作業系統說送出 reqeust,作業系統跟網路說要送出 request 給 google 的 server,把資料送到 dataBase,google server 回傳 response 給網路,網路再把 response 交還給作業系統,之後作業系統把 response 給 chrome 瀏覽器,最後 google chrome 在顯示出結果。
其實在這個HTTP message 中分為「發送 request」 及 「接收 response」,裡面有規範固定的格式,讓大家可以依照 HTTP 規則傳達網路訊息,HTTP message 內的組成為 starter-line、HTTP headers、empty line、body。
1.starter-line:描述要用什麼方法實現 request,如POST
、GET
、PATCH
等,及 status code(如:200 OK)。
syntax: request method, request target, HTTP version
example: POST /?id=1 HTTP/1.1
HTTP/1.1 200 OK
2. HTTP headers:附加的重要資訊,如訂便當服務,要不要辣,何時外送抵達,要不要免洗餐具。在實際網路應用上,有標示哪一款瀏覽器(Chrome、IE、FireFox)、內容形式為 json、html等。在 request 中會出現幾類的 headers,有 general headers(如:via
)、request headers(如:User-Agent
或 Accept
)、formerly entity headers(如:content-length
),舉例的 headers 先有個印象即可。
現在瞭解 HTTP request 和 response 會傳送什麼樣的資料後,就可以來研究一下request(url, function(error, response, body) => {...})
。
舉一個餐廳點餐的例子:
用餐的客人向餐廳內的服務員點餐(發出 request):我要跟廚師點一客七分熟的腓力牛排,附蘑菇醬汁,然後服務員會回覆(response):成功點餐或此品項已售罄。
<客人的 request>
header:
牛排熟度:七分熟
醬汁:蘑菇醬
body:
腓力牛排
<服務員的 response>
200 OK
---------
成功點餐
<服務員的 response>
400 error
---------
此品項已賣光
一般人在點餐時,發出請求(request)會希望得到的回覆是有沒有錯誤(error)、答覆(response)、確切內容(body),就如請求 API 文件內的資料時一樣,輸入參數(parameter)在向 API 文件請求資料的時候,也會希望可以獲得 API 文件裡面的資料(body)、回覆(response)或者出錯時的 error 的資訊。
因為 request 只是一個動作的要求,具體要求什麼東西,做什麼事,需要另外寫清楚,例如:要求進去這個網頁,需要進去什麼網頁(目的地),進去網頁後要做什麼?以串接API文件為例子的話,就是發出 request 要使用這個 API 文件內的資訊,目的地就是該 API 文件的 URL,要做什麼的話,就是利用 function 包住要做的事情(將API文件內的資訊抓出來)。
透過串接 API 文件裡的資訊來實際演練 HTTP request 和 response,利用 Node.js 及 npm modules 的 request 循序漸進的練習。
client-id
、accept
、HTTP basic authorization
,以下為練習的例子:request.post
新增資料時,在 headers 裡加入content-type
,讓新增的資料符合格式。HTTP 基本認證
搭配學習。user-agent
來辨別瀏覽器。Q3: API 是什麼? RESTful API 又是什麼?
API 是什麼?
常常可以在 App Store 或者 Google Play 上看見氣象跟星象有關的 app,或者是在網誌上看食記的時候,會看到文章內鑲嵌 Google Map 地圖,網誌跟 app 的資訊都是來自 Google Map 跟氣象局的資料。在 Google Map 和氣象局的角度,就是提供資料,而在 app 和食記的角度,就是在使用資料,這樣一來一往就是交換資料,但是一般人不會想把自己的資料直接分享給別人使用,可能會有一些隱私顧慮,所以利用另一種形式將提供資料給大眾使用,這樣有利於大眾做一些新功能的開發,例如:使用他方的星象跟氣象資料,製作的新 app,或者是幫助食記圖像化餐廳位置的 Google Map。那這些資料種類繁多、資料龐大,怎麼樣讓大家可以擷取使用?就需要訂立一個統一化的格式、規範跟環境,讓大家不僅可以分享資料,也可以使用這些資料。 這些資料的提供跟使用,就是使用 API 這個方法,API 全名是應用程式介面(application programming interface),重點是「介面」這個詞,先前提到,若要讓大家都看的懂資料,就要有統一的格式跟環境,這個 API 就是中間的媒介,讓大家可以擷取跟提供資料,有了資料的統一格式跟資料說明,再搭配程式語言的輔助,讓大家可以成功的將資料交換,讓更多人可以使用資料跟開發新功能。
RESTful API
RESTful API 是基於設計風格所創造,對 data 的動作如:新增、修改、刪除、取得,剛剛好對應到 HTTP method 的 GET
、POST
、DELETE
、GET
。如果是 HTTP method 的話,要先瞭解每個指令的意義跟使用方式,而 RESTful API 將這些指令對應成白話的動作:新增、刪除、取得。
Q4: try{...} catch() {...} throw 要怎麼使用?為什麼需要?
有時候再執行 js 時,不知道哪裡出了錯,可以使用 try catch ,抓到某個錯誤時,會 console.log()出的資訊,來看哪裡發生。其實也可以用在預期錯誤,在執行發生錯誤時,提供錯誤修正的提示。
throw
是直接丟出訊息,可以這樣使用 throw 'Opps!!!'
,只要執行這一行,就會出現 'Opps!!!'
。
HTTP/1.1 — 訊息格式 (Message Format)
npm modules -- request
HTTP headers
Link to Header
目標:熟悉網路基礎知識及練習使用 Node.js 串接基本的 API
具備知識: Node.js 串接基本的 API、網路基礎知識
以下為題目解說與所學內容,並於最後有附上解題過程。
Lv 1: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}
Lv 2: https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}
Lv3: https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}
POST
method。content type 為:application/x-www-form-urlencoded
。在此使用 request 的 npm 套件,因此需要使用 POST
的話,需要符合格式傳送,這個格式就是上述的 content-type
,在 HTTP 內容類型 (Content-Type) 提到「普遍用於 HTML 中的 POST 表單 (e.g., 提交帳號密碼),是『類似百分比編碼的鍵值對』形式,例如:『name=%E5%8B%9D&password=9487』」
利用 HTTP GET vs POST 的解說,對 request 中 GET method
做進一步瞭解,GET
有查詢/檢索/獲取的意思,如果需要使用GET
來找到書籍的話,需要額外在表單(form)輸入參數(parameter)中,會做 URL 編碼 (URL-Encoding)在 URL 透過查詢(query)會以鍵值對(key value)的形式顯示,例如:查詢幾歲的女生,key 為年紀,因此將 key 稱 age,value 為歲數,所以將 value 設為 24,加上條件為女生,再透過 get
查詢生成的 URL:https://echo.paw.cloud:443/hello/world?age=24&gender=female。
其中,urlencoded
就是產生編碼的意思,如果 form 內的資料呈現以下格式:
form:{
name: 'littlePrince',
ISBN: '324232&123=3'
}
會在 URL加上資訊為 name=littlePrince&ISBN=324232&123=3
,那這樣 server 會搞不清楚 form 內的 ISBN 為324232
還是 324232&123=3
,因此需要透過編碼形式的轉換,避免混淆。在 URL 編碼中,會把字符分成兩種:保留字符(具特殊字元)及未保留字符,在 URL 編碼中會將特殊字符做轉換,如此一來,ISBN: 324232&123=3
就會轉換成324232%26123%3d3
,這樣透過編碼後,就可以正確帶入資訊。
Lv 4: https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}
process.argv
再執行 node.js 時輸入參數來印出書籍。Lv 5: https://lidemy-http-challenge.herokuapp.com/lv5?token={HarukiMurakami}
POST
method 在 content-type
上做區別。新文件:https://gist.github.com/aszx87410/1e5e5105c1c35197f55c485a88b0328a
Lv 6: https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}
Lv 7: https://lidemy-http-challenge.herokuapp.com/lv7?token=%7BSECurityIsImPORTant%7D
Lv 8: https://lidemy-http-challenge.herokuapp.com/lv8?token={HsifnAerok}
Lv9: http://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}
條件
Lv10: http://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}
Lv 1: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=jean
Tip: 填上名字就行了!
Lv 2: https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56
Tip: id 從 54 ~ 58 一個一個輸入
Lv 3: https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}&id=1989
Tip: 見 API 文件上,新增書籍需要使用到 POST method,在 headers 內,除了寫提交表單(form),還要記得內容格式(content-type)為application/x-www-form-urlencoded
(default),其他格式參見 npm request
,表單格式,依照 API 文件說明,參數有:「name: 書名, ISBN: 書籍編號」,最後再使用 console.log(body)
,會印出{"message":"新增成功","id":"1989"}
。
Lv 4: https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}&id=79
法 1: 自己想到的解法:尋找書籍含有「世界」二字,可以使用 process.argv
的參數,在執行 node xx.js 時,加入所需參數「世界」,並印出所有包含「世界」的書名,尋找作者「村上春樹」。
const request = require('request')
const process = require('process')
if ( process.argv[2] === 'read') {
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/books/',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'},
},
(error, response, body) => {
const json = JSON.parse(body)
for (let i=0; i< json.length ; i++) {
if (json[i].name.indexOf(process.argv[3]) !== -1) {
console.log(json[i])
}
}
}
)
}
$ node lv4.js read 世界
{ id: 2, name: '當我想你時,全世界都救不了我', author: '肆一', ISBN: '5549173495' }
{ id: 27, name: '從你的全世界路過', author: '張嘉佳', ISBN: '8426216529' }
{ id: 79, name: '世界末日與冷酷異境', author: '村上春樹', ISBN: '9571313408' }
{
id: 90,
name: '文學的40堂公開課:從神話到當代暢銷書,文學如何影響我們、帶領我們理解這個世界',
author: '約翰.薩德蘭',
ISBN: '7978376866'
}
法 2: 參考他人的解法:利用 ‵encodeURI()‵ 將「世界」編碼,帶入 API 網址搜尋後印出結果。
Lv 5:
const request = require('request')
const process = require('process')
if (process.argv[2] === 'delete') {
let idNum = process.argv[3];
request.delete(
'https://lidemy-http-challenge.herokuapp.com/api/books/'+idNum,
(error, response, body) => {
if (!error && response.statusCode >= 200) {
console.log('body',body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
}
$ node lv5.js delete 23
{"message":"\n咦...是刪掉了沒錯,但總覺得哪裡怪怪的,算了,先這樣吧!下一關的 token 為 {CHICKENCUTLET}\n"}
statusCode: 200
lv 6: https://lidemy-http-challenge.herokuapp.com/lv6?token=%7BCHICKENCUTLET%7D&email=lib@lidemy.com
從 API 文件中,得知 username: password 的內容格式,拿去 Base64 編碼,得到Authorization: xxxx
後,放進 headers
裡面。
const request = require('request')
//https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/me',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
console.log('body:',body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
$ node lv6.js
body: {"username":"admin","email":"lib@lidemy.com"}
statusCode: 200
lv 7:
依照 API 文件刪除書籍的 request method: delete,再用 console.log 印出 body 及 statusCode 確認結果。
const request = require('request')
if (process.argv[2] === 'delete') {
let idNum = process.argv[3];
request.delete(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/'+idNum,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log('body:',json.message)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
}
$ node lv7.js delete 89
body:
希望下一次進這本書的時候不會再被偷走了。下一關的 token 為 {HsifnAerok}
statusCode: 200
Lv 8:
node xx..js read 我
尋找書本,但是將題目所要求的條件一:作者名稱 4 個字,及條件二: ISBN 末碼為 7 的書本利用 if 條件式挑出來,印出書本的 id,再使用 node xx.js update <idNumber> <BookNewISBN>
將書本更新資訊。const request = require('request')
const process = require('process')
if (process.argv[2] === 'update') {
let idNum = process.argv[3];
let newISBN = process.argv[4];
request.patch(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/'+idNum,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
},
form: {
ISBN: newISBN
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log('body message:',json.message)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
} else if (process.argv[2] === 'read') {
let keyword = process.argv[3]
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books?q=',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
},
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
for (let i=0; i< json.length; i++) {
let bookname=json[i].name;
let thisISBN = json[i].ISBN
let thisAuthor = json[i].author
if ( bookname.indexOf(process.argv[3]) !== -1) {
if (thisAuthor.length === 4) {
if (thisISBN[thisISBN.length-1] === '7') {
//console.log('thisISBN.length:',thisISBN.length-1, thisISBN[thisISBN.length-1])
console.log(json[i].id, json[i].name, json[i].ISBN)
}
}
}
}
}
console.log(`statusCode: ${response.statusCode}`)
}
)
}
$ node lv8.js read 我
72 日日好日:茶道教我的幸福15味【電影書腰版】 9981835427
statusCode: 200
$ node lv8.js update 72 9981835423
body message:
希望之後他們能引進語音輸入系統,我就只要講講話就好。下一關的 token 為 {NeuN}
statusCode: 200
Lv9: http://lidemy-http-challenge.herokuapp.com/lv9?token=%7BNeuN%7D&version=1A4938Jl7
什麼是 User Agent 呢?中文為「使用者代理」,當 server 端一旦收到 client 端的身份識別後,就會做出相對的回應,例如:client 端是從電腦端還是手機端,這樣就 server 端就可以 response 出手機形式的網頁或者是電腦形式的網頁,提升 client 的使用體驗。
那 IE6 的 user Agent 是什麼呢?搜尋了 MDN 等等,好像都是其他版本的瀏覽器,例如 Chrome、IE9等等,然後複製上 user Agent,得到的是 Invalid
。所以又搜尋了一番!終於在 stackFlow 上找到 IE6 的 user Agent。
const request = require('request')
const process = require('process')
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'X-Library-Number': '20',
'User-Agent': 'MMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log(body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
$ node lv9_1.js
body {"message":"success","version":"1A4938Jl7","owner":"lib","createdAt":"121290329301"}
statusCode: 200
Lv 10: http://lidemy-http-challenge.herokuapp.com/lv10?token=%7BduZDsG3tvoA%7D&num=9613
參考別種解法:Lidemy HTTP Challenge 破關紀錄
什麼是 URLEncode:[轉] 混亂的 URLEncode
URL 編碼意思:UrlEncodeDecode
什麼是 HTTP 基本認證:HTTP基本認證 Wikipedia
什麼是 userAgent:要怎麼辨別使用者瀏覽者用哪種瀏覽器呢?用UserAgent是最簡單的方式喔!
IE6 的 userAgent:Why is IE9 sending a user agent string of IE6?
Link to Header
目標:熟悉網路基礎知識及練習使用 Node.js 串接基本的 API
具備知識: Node.js 串接基本的 API、網路基礎知識
以下為題目解說與所學內容,並於最後有附上解題過程。
Lv 1: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}
Lv 2: https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}
Lv3: https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}
POST
method。content type 為:application/x-www-form-urlencoded
。在此使用 request 的 npm 套件,因此需要使用 POST
的話,需要符合格式傳送,這個格式就是上述的 content-type
,在 HTTP 內容類型 (Content-Type) 提到「普遍用於 HTML 中的 POST 表單 (e.g., 提交帳號密碼),是『類似百分比編碼的鍵值對』形式,例如:『name=%E5%8B%9D&password=9487』」
利用 HTTP GET vs POST 的解說,對 request 中 GET method
做進一步瞭解,GET
有查詢/檢索/獲取的意思,如果需要使用GET
來找到書籍的話,需要額外在表單(form)輸入參數(parameter)中,會做 URL 編碼 (URL-Encoding)在 URL 透過查詢(query)會以鍵值對(key value)的形式顯示,例如:查詢幾歲的女生,key 為年紀,因此將 key 稱 age,value 為歲數,所以將 value 設為 24,加上條件為女生,再透過 get
查詢生成的 URL:https://echo.paw.cloud:443/hello/world?age=24&gender=female。
其中,urlencoded
就是產生編碼的意思,如果 form 內的資料呈現以下格式:
form:{
name: 'littlePrince',
ISBN: '324232&123=3'
}
會在 URL加上資訊為 name=littlePrince&ISBN=324232&123=3
,那這樣 server 會搞不清楚 form 內的 ISBN 為324232
還是 324232&123=3
,因此需要透過編碼形式的轉換,避免混淆。在 URL 編碼中,會把字符分成兩種:保留字符(具特殊字元)及未保留字符,在 URL 編碼中會將特殊字符做轉換,如此一來,ISBN: 324232&123=3
就會轉換成324232%26123%3d3
,這樣透過編碼後,就可以正確帶入資訊。
Lv 4: https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}
process.argv
再執行 node.js 時輸入參數來印出書籍。Lv 5: https://lidemy-http-challenge.herokuapp.com/lv5?token={HarukiMurakami}
POST
method 在 content-type
上做區別。新文件:https://gist.github.com/aszx87410/1e5e5105c1c35197f55c485a88b0328a
Lv 6: https://lidemy-http-challenge.herokuapp.com/lv6?token={CHICKENCUTLET}
Lv 7: https://lidemy-http-challenge.herokuapp.com/lv7?token=%7BSECurityIsImPORTant%7D
Lv 8: https://lidemy-http-challenge.herokuapp.com/lv8?token={HsifnAerok}
Lv9: http://lidemy-http-challenge.herokuapp.com/lv9?token={NeuN}
條件
Lv10: http://lidemy-http-challenge.herokuapp.com/lv10?token={duZDsG3tvoA}
Lv 1: https://lidemy-http-challenge.herokuapp.com/lv1?token={GOGOGO}&name=jean
Tip: 填上名字就行了!
Lv 2: https://lidemy-http-challenge.herokuapp.com/lv2?token={HellOWOrld}&id=56
Tip: id 從 54 ~ 58 一個一個輸入
Lv 3: https://lidemy-http-challenge.herokuapp.com/lv3?token={5566NO1}&id=1989
Tip: 見 API 文件上,新增書籍需要使用到 POST method,在 headers 內,除了寫提交表單(form),還要記得內容格式(content-type)為application/x-www-form-urlencoded
(default),其他格式參見 npm request
,表單格式,依照 API 文件說明,參數有:「name: 書名, ISBN: 書籍編號」,最後再使用 console.log(body)
,會印出{"message":"新增成功","id":"1989"}
。
Lv 4: https://lidemy-http-challenge.herokuapp.com/lv4?token={LEarnHOWtoLeArn}&id=79
法 1: 自己想到的解法:尋找書籍含有「世界」二字,可以使用 process.argv
的參數,在執行 node xx.js 時,加入所需參數「世界」,並印出所有包含「世界」的書名,尋找作者「村上春樹」。
const request = require('request')
const process = require('process')
if ( process.argv[2] === 'read') {
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/books/',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'},
},
(error, response, body) => {
const json = JSON.parse(body)
for (let i=0; i< json.length ; i++) {
if (json[i].name.indexOf(process.argv[3]) !== -1) {
console.log(json[i])
}
}
}
)
}
$ node lv4.js read 世界
{ id: 2, name: '當我想你時,全世界都救不了我', author: '肆一', ISBN: '5549173495' }
{ id: 27, name: '從你的全世界路過', author: '張嘉佳', ISBN: '8426216529' }
{ id: 79, name: '世界末日與冷酷異境', author: '村上春樹', ISBN: '9571313408' }
{
id: 90,
name: '文學的40堂公開課:從神話到當代暢銷書,文學如何影響我們、帶領我們理解這個世界',
author: '約翰.薩德蘭',
ISBN: '7978376866'
}
法 2: 參考他人的解法:利用 ‵encodeURI()‵ 將「世界」編碼,帶入 API 網址搜尋後印出結果。
Lv 5:
const request = require('request')
const process = require('process')
if (process.argv[2] === 'delete') {
let idNum = process.argv[3];
request.delete(
'https://lidemy-http-challenge.herokuapp.com/api/books/'+idNum,
(error, response, body) => {
if (!error && response.statusCode >= 200) {
console.log('body',body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
}
$ node lv5.js delete 23
{"message":"\n咦...是刪掉了沒錯,但總覺得哪裡怪怪的,算了,先這樣吧!下一關的 token 為 {CHICKENCUTLET}\n"}
statusCode: 200
lv 6: https://lidemy-http-challenge.herokuapp.com/lv6?token=%7BCHICKENCUTLET%7D&email=lib@lidemy.com
從 API 文件中,得知 username: password 的內容格式,拿去 Base64 編碼,得到Authorization: xxxx
後,放進 headers
裡面。
const request = require('request')
//https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/me',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
console.log('body:',body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
$ node lv6.js
body: {"username":"admin","email":"lib@lidemy.com"}
statusCode: 200
lv 7:
依照 API 文件刪除書籍的 request method: delete,再用 console.log 印出 body 及 statusCode 確認結果。
const request = require('request')
if (process.argv[2] === 'delete') {
let idNum = process.argv[3];
request.delete(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/'+idNum,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log('body:',json.message)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
}
$ node lv7.js delete 89
body:
希望下一次進這本書的時候不會再被偷走了。下一關的 token 為 {HsifnAerok}
statusCode: 200
Lv 8:
node xx..js read 我
尋找書本,但是將題目所要求的條件一:作者名稱 4 個字,及條件二: ISBN 末碼為 7 的書本利用 if 條件式挑出來,印出書本的 id,再使用 node xx.js update <idNumber> <BookNewISBN>
將書本更新資訊。const request = require('request')
const process = require('process')
if (process.argv[2] === 'update') {
let idNum = process.argv[3];
let newISBN = process.argv[4];
request.patch(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books/'+idNum,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
},
form: {
ISBN: newISBN
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log('body message:',json.message)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
} else if (process.argv[2] === 'read') {
let keyword = process.argv[3]
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/books?q=',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='
},
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
for (let i=0; i< json.length; i++) {
let bookname=json[i].name;
let thisISBN = json[i].ISBN
let thisAuthor = json[i].author
if ( bookname.indexOf(process.argv[3]) !== -1) {
if (thisAuthor.length === 4) {
if (thisISBN[thisISBN.length-1] === '7') {
//console.log('thisISBN.length:',thisISBN.length-1, thisISBN[thisISBN.length-1])
console.log(json[i].id, json[i].name, json[i].ISBN)
}
}
}
}
}
console.log(`statusCode: ${response.statusCode}`)
}
)
}
$ node lv8.js read 我
72 日日好日:茶道教我的幸福15味【電影書腰版】 9981835427
statusCode: 200
$ node lv8.js update 72 9981835423
body message:
希望之後他們能引進語音輸入系統,我就只要講講話就好。下一關的 token 為 {NeuN}
statusCode: 200
Lv9: http://lidemy-http-challenge.herokuapp.com/lv9?token=%7BNeuN%7D&version=1A4938Jl7
什麼是 User Agent 呢?中文為「使用者代理」,當 server 端一旦收到 client 端的身份識別後,就會做出相對的回應,例如:client 端是從電腦端還是手機端,這樣就 server 端就可以 response 出手機形式的網頁或者是電腦形式的網頁,提升 client 的使用體驗。
那 IE6 的 user Agent 是什麼呢?搜尋了 MDN 等等,好像都是其他版本的瀏覽器,例如 Chrome、IE9等等,然後複製上 user Agent,得到的是 Invalid
。所以又搜尋了一番!終於在 stackFlow 上找到 IE6 的 user Agent。
const request = require('request')
const process = require('process')
request.get(
{
url: 'https://lidemy-http-challenge.herokuapp.com/api/v2/sys_info',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic YWRtaW46YWRtaW4xMjM=',
'X-Library-Number': '20',
'User-Agent': 'MMozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)'
}
},
(error, response, body) => {
if (!error && response.statusCode >= 200) {
const json = JSON.parse(body)
console.log(body)
console.log(`statusCode: ${response.statusCode}`)
}
}
)
$ node lv9_1.js
body {"message":"success","version":"1A4938Jl7","owner":"lib","createdAt":"121290329301"}
statusCode: 200
Lv 10: http://lidemy-http-challenge.herokuapp.com/lv10?token=%7BduZDsG3tvoA%7D&num=9613
參考別種解法:Lidemy HTTP Challenge 破關紀錄
什麼是 URLEncode:[轉] 混亂的 URLEncode
URL 編碼意思:UrlEncodeDecode
什麼是 HTTP 基本認證:HTTP基本認證 Wikipedia
什麼是 userAgent:要怎麼辨別使用者瀏覽者用哪種瀏覽器呢?用UserAgent是最簡單的方式喔!
IE6 的 userAgent:Why is IE9 sending a user agent string of IE6?
npm install -g json-server
安裝 json-server npm 套件。
結果裝成npm install json-server
,就安裝失敗(附註:詳見另一篇,還沒寫好)
之後亂查,還 google 到了 curl -X -GET https://...
,好像是可以用在新增 JSON 資料(curl -X -POST
)、取得資料(curl -X -GET
)、刪除資料(curl -X -DELETE
)。
好像想起來了,可以用在批次下載指令,以前做報告時,我有用過在下載每一小時的衛星雲圖。我這次嘗試使用curl -X -GET https://... > db.json
下載後,印到 db.json 檔案裡。後來一想,API 串接的概念,就是資料交換,把資料下載下來好像哪裡不太對,因為不正是資料太大或者是想要借用別人的資料,才使用資料交換的概念嗎?如果下載下來,好像不太符合初衷。
又繼續 Google,看到了這個網頁 JSON Server tutorial
簡直是救星,掃描了一下內容,發現關鍵字get_request.js
,還不拿來參考一下,還安裝了 npm 套件的 axios,這次學聰明了,使用 npm install -g axios
就成功安裝。
// get_request.js
const axios = require('axios');
axios.get('http://localhost:3000/users')
.then(resp => {
data = resp.data;
data.forEach(e => {
console.log(`${e.first_name}, ${e.last_name}, ${e.email}`);
});
})
.catch(error => {
console.log(error);
});
然後我就很開心的拿來修改,把 data.forEach(e => {... data = resp.data}
的部分改成我要的迴圈:列出前十本書籍的 id 以及書名,輸出跟 index.js 程式碼如下:
// index.js
const axios = require('axios');
axios.get('https://lidemy-book-store.herokuapp.com/books')
.then(resp => {
data = resp.data;
for (let i=1; i<=10; i++) {
console.log(data[i].id, data[i].name)
}
})
.catch(error => {
console.log(error);
});
# @terminal
$ node index.js # 執行 javascript,輸出前十本書
1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
4 念念時光真味
5 蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】
6 苦雨之地
7 你已走遠,我還在練習道別
8 想把餘生的溫柔都給你
9 你是我最熟悉的陌生人
10 偷書賊(25萬本紀念版本)
然後我就抱著喜悅開心的睡覺了,也沒有細查什麼是 axios
。結果隔天早上熊熊想到,那到底是什麼套件啊...這麼神奇,而且我也看不懂 then
的意思,這樣交作業好像不太負責任。查了一下 axios
好像跟 vue 有關,又仔細想想,好像還沒學到 vue,所以不能使用,所以我昨天花了半天繞一大圈的找資料,最後又回歸了最原始的方法,就是回去看 [NET101] API串接的實戰影片。
想說如法炮製,試試看 console.log(body)
會印出什麼資料。
// index.js 範例 1
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books',
function (error, response, body) {
console.log('body:',body) // 現在要測試印出的檔案資料長什麼樣
}
)
$ node index.js
[
{
"id": 1,
"name": "克雷的橋"
},
{
"id": 2,
"name": "當我想你時,全世界都救不了我"
},
{
"id": 3,
"name": "我殺的人與殺我的人"
},
{
"id": 4,
"name": "念念時光真味"
},
{
"id": 5,
"name": "蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】"
},
{
"id": 6,
"name": "苦雨之地"
},
{
"id": 7,
"name": "你已走遠,我還在練習道別"
},
{
"id": 8,
"name": "想把餘生的溫柔都給你"
},
{
"id": 9,
"name": "你是我最熟悉的陌生人"
},
{
"id": 10,
"name": "偷書賊(25萬本紀念版本)"
},
{
"id": 11,
"name": "在回憶消逝之前"
},
{
"id": 12,
"name": "懲罰"
},
{
"id": 13,
"name": "雲邊有個小賣部"
},
{
"id": 14,
"name": "颶光典籍三部曲:引誓之劍(上下冊套書)"
},
{
"id": 15,
"name": "危險維納斯"
},
{
"id": 16,
"name": "大旱"
},
{
"id": 17,
"name": "最後的再見"
},
{
"id": 18,
"name": "解憂雜貨店【暢銷35萬冊暖心紀念版】:回饋讀者,一次收藏2款書封!"
},
{
"id": 19,
"name": "高山上的小郵局:獻給書信和手寫年代的溫暖情詩,2019年最治癒人心的高暖度小說"
},
{
"id": 20,
"name": "在場證明"
}
]
結果印出書本目錄,現在我只需要前十本,所以需要使用拿手的迴圈來找出十本書,於是我加了以下迴圈。
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books' ,
function (error, response, body) {
try {
/* 新增這個迴圈, */
for (let i=0; i<10; i++) {
console.log(body[i].id, body[i].name)
}
/* 新增以上 */
} catch(error){
cosole.log(error)
}
}
)
結果印出 undefined。
$ node index.js
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
現在就要來看看到底發生什麼事情,console.log(body[i].id, body[i].name)
中變數的表示法是 object 的表示法,但是 body 是什麼型態呢?使用 console.log(typeof(body))
後發現是 string 的變數型態。就想到 [NET101] 7-3 API 串接實戰的範例 1:DELETE 中的 const json = JSON.parse(body) //JSON 格式的字串
,看不懂 JSON.parse() MDN 的用法,就去查詢發現: API 文件內的格式是JSON字串,所以我需要把資料從 JSON 格式的字串轉換成 JavaScript 的物件,這樣才能使用 body[i].id
在 js 檔案內擷取資料。
修改 js 檔案,如下:
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books' ,
function (error, response, body) {
/* 新增以下此行:查詢一下資料( body )的資料型態,發現是 string */
// console.log(typeof(body)) //typeof(body) is string
try {
/* 新增以下此行:把 JSON 格式的字串轉換成 JavaScript 的物件 */
const json = JSON.parse(body) //typeof(json) is object
for (let i=0; i<10; i++) {
console.log(json[i].id, json[i].name)
}
} catch(error){
cosole.log(error)
}
}
)
再輸出一次:
$ node index.js
1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
4 念念時光真味
5 蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】
6 苦雨之地
7 你已走遠,我還在練習道別
8 想把餘生的溫柔都給你
9 你是我最熟悉的陌生人
10 偷書賊(25萬本紀念版本)
]]>npm install -g json-server
安裝 json-server npm 套件。
結果裝成npm install json-server
,就安裝失敗(附註:詳見另一篇,還沒寫好)
之後亂查,還 google 到了 curl -X -GET https://...
,好像是可以用在新增 JSON 資料(curl -X -POST
)、取得資料(curl -X -GET
)、刪除資料(curl -X -DELETE
)。
好像想起來了,可以用在批次下載指令,以前做報告時,我有用過在下載每一小時的衛星雲圖。我這次嘗試使用curl -X -GET https://... > db.json
下載後,印到 db.json 檔案裡。後來一想,API 串接的概念,就是資料交換,把資料下載下來好像哪裡不太對,因為不正是資料太大或者是想要借用別人的資料,才使用資料交換的概念嗎?如果下載下來,好像不太符合初衷。
又繼續 Google,看到了這個網頁 JSON Server tutorial
簡直是救星,掃描了一下內容,發現關鍵字get_request.js
,還不拿來參考一下,還安裝了 npm 套件的 axios,這次學聰明了,使用 npm install -g axios
就成功安裝。
// get_request.js
const axios = require('axios');
axios.get('http://localhost:3000/users')
.then(resp => {
data = resp.data;
data.forEach(e => {
console.log(`${e.first_name}, ${e.last_name}, ${e.email}`);
});
})
.catch(error => {
console.log(error);
});
然後我就很開心的拿來修改,把 data.forEach(e => {... data = resp.data}
的部分改成我要的迴圈:列出前十本書籍的 id 以及書名,輸出跟 index.js 程式碼如下:
// index.js
const axios = require('axios');
axios.get('https://lidemy-book-store.herokuapp.com/books')
.then(resp => {
data = resp.data;
for (let i=1; i<=10; i++) {
console.log(data[i].id, data[i].name)
}
})
.catch(error => {
console.log(error);
});
# @terminal
$ node index.js # 執行 javascript,輸出前十本書
1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
4 念念時光真味
5 蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】
6 苦雨之地
7 你已走遠,我還在練習道別
8 想把餘生的溫柔都給你
9 你是我最熟悉的陌生人
10 偷書賊(25萬本紀念版本)
然後我就抱著喜悅開心的睡覺了,也沒有細查什麼是 axios
。結果隔天早上熊熊想到,那到底是什麼套件啊...這麼神奇,而且我也看不懂 then
的意思,這樣交作業好像不太負責任。查了一下 axios
好像跟 vue 有關,又仔細想想,好像還沒學到 vue,所以不能使用,所以我昨天花了半天繞一大圈的找資料,最後又回歸了最原始的方法,就是回去看 [NET101] API串接的實戰影片。
想說如法炮製,試試看 console.log(body)
會印出什麼資料。
// index.js 範例 1
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books',
function (error, response, body) {
console.log('body:',body) // 現在要測試印出的檔案資料長什麼樣
}
)
$ node index.js
[
{
"id": 1,
"name": "克雷的橋"
},
{
"id": 2,
"name": "當我想你時,全世界都救不了我"
},
{
"id": 3,
"name": "我殺的人與殺我的人"
},
{
"id": 4,
"name": "念念時光真味"
},
{
"id": 5,
"name": "蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】"
},
{
"id": 6,
"name": "苦雨之地"
},
{
"id": 7,
"name": "你已走遠,我還在練習道別"
},
{
"id": 8,
"name": "想把餘生的溫柔都給你"
},
{
"id": 9,
"name": "你是我最熟悉的陌生人"
},
{
"id": 10,
"name": "偷書賊(25萬本紀念版本)"
},
{
"id": 11,
"name": "在回憶消逝之前"
},
{
"id": 12,
"name": "懲罰"
},
{
"id": 13,
"name": "雲邊有個小賣部"
},
{
"id": 14,
"name": "颶光典籍三部曲:引誓之劍(上下冊套書)"
},
{
"id": 15,
"name": "危險維納斯"
},
{
"id": 16,
"name": "大旱"
},
{
"id": 17,
"name": "最後的再見"
},
{
"id": 18,
"name": "解憂雜貨店【暢銷35萬冊暖心紀念版】:回饋讀者,一次收藏2款書封!"
},
{
"id": 19,
"name": "高山上的小郵局:獻給書信和手寫年代的溫暖情詩,2019年最治癒人心的高暖度小說"
},
{
"id": 20,
"name": "在場證明"
}
]
結果印出書本目錄,現在我只需要前十本,所以需要使用拿手的迴圈來找出十本書,於是我加了以下迴圈。
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books' ,
function (error, response, body) {
try {
/* 新增這個迴圈, */
for (let i=0; i<10; i++) {
console.log(body[i].id, body[i].name)
}
/* 新增以上 */
} catch(error){
cosole.log(error)
}
}
)
結果印出 undefined。
$ node index.js
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
undefined undefined
現在就要來看看到底發生什麼事情,console.log(body[i].id, body[i].name)
中變數的表示法是 object 的表示法,但是 body 是什麼型態呢?使用 console.log(typeof(body))
後發現是 string 的變數型態。就想到 [NET101] 7-3 API 串接實戰的範例 1:DELETE 中的 const json = JSON.parse(body) //JSON 格式的字串
,看不懂 JSON.parse() MDN 的用法,就去查詢發現: API 文件內的格式是JSON字串,所以我需要把資料從 JSON 格式的字串轉換成 JavaScript 的物件,這樣才能使用 body[i].id
在 js 檔案內擷取資料。
修改 js 檔案,如下:
const request = require('request');
request(
'https://lidemy-book-store.herokuapp.com/books' ,
function (error, response, body) {
/* 新增以下此行:查詢一下資料( body )的資料型態,發現是 string */
// console.log(typeof(body)) //typeof(body) is string
try {
/* 新增以下此行:把 JSON 格式的字串轉換成 JavaScript 的物件 */
const json = JSON.parse(body) //typeof(json) is object
for (let i=0; i<10; i++) {
console.log(json[i].id, json[i].name)
}
} catch(error){
cosole.log(error)
}
}
)
再輸出一次:
$ node index.js
1 克雷的橋
2 當我想你時,全世界都救不了我
3 我殺的人與殺我的人
4 念念時光真味
5 蜂蜜花火【致年少時光‧限量插畫設計書衣典藏版】
6 苦雨之地
7 你已走遠,我還在練習道別
8 想把餘生的溫柔都給你
9 你是我最熟悉的陌生人
10 偷書賊(25萬本紀念版本)
]]>
一開始想用 ls
來確認一下有沒有 node_module 跟 package.json ,這樣就可以知道有沒有引入 npm (Node.js 套件管理程式)
。
開一個新資料夾,建立 index.js,然後想要從 npm 引入 module(npm install
)發生的問題如下:
$ ls -l
total 0
-rw-r--r--@ 1 jeanlu staff 0 May 4 11:59 index.js
$ npm install request
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN lioj@1.0.0 No description
npm WARN lioj@1.0.0 No repository field.
$ ls
index.js
結果我再一次 ls
,我發現並沒有 package.json,表示 npm install request
失敗。在想說為什麼沒有這些檔案時,把 npm WARN lioj@1.0.0 No description
npm WARN lioj@1.0.0 No repository field
查了一下 google,發現這篇
Can't istall Node.js Packages properly on Shared hosting 的 1F Answer。原來是需要 npm init
,初始化 npm 後,確認有沒有 package.json 檔案生成。
$ npm init
... # 一直按 enter
Is this OK? (yes)
$ ls # 確認有 package.json 生成, npm 安裝完成
index.js package.json
成功引入 npm (套件管理程式),會生成 package.json。如此一來,下一步驟就可以來下載所需要的套件囉,下載好我需要的套件「request」後會生成 package-lock.json 及 node_modules。
$ npm install request # 下載 npm 套件「request」
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN week4_json@1.0.0 No description
npm WARN week4_json@1.0.0 No repository field.
+ request@2.88.2
added 47 packages from 58 contributors and audited 47 packages in 2.641s
2 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ ls # 下載好套件後,會有新的檔案生成:package-lock.json, node_modules
index.js package-lock.json
node_modules package.json
然後就可以開始使用了!
]]>一開始想用 ls
來確認一下有沒有 node_module 跟 package.json ,這樣就可以知道有沒有引入 npm (Node.js 套件管理程式)
。
開一個新資料夾,建立 index.js,然後想要從 npm 引入 module(npm install
)發生的問題如下:
$ ls -l
total 0
-rw-r--r--@ 1 jeanlu staff 0 May 4 11:59 index.js
$ npm install request
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm WARN lioj@1.0.0 No description
npm WARN lioj@1.0.0 No repository field.
$ ls
index.js
結果我再一次 ls
,我發現並沒有 package.json,表示 npm install request
失敗。在想說為什麼沒有這些檔案時,把 npm WARN lioj@1.0.0 No description
npm WARN lioj@1.0.0 No repository field
查了一下 google,發現這篇
Can't istall Node.js Packages properly on Shared hosting 的 1F Answer。原來是需要 npm init
,初始化 npm 後,確認有沒有 package.json 檔案生成。
$ npm init
... # 一直按 enter
Is this OK? (yes)
$ ls # 確認有 package.json 生成, npm 安裝完成
index.js package.json
成功引入 npm (套件管理程式),會生成 package.json。如此一來,下一步驟就可以來下載所需要的套件囉,下載好我需要的套件「request」後會生成 package-lock.json 及 node_modules。
$ npm install request # 下載 npm 套件「request」
npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
npm WARN deprecated har-validator@5.1.5: this library is no longer supported
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN week4_json@1.0.0 No description
npm WARN week4_json@1.0.0 No repository field.
+ request@2.88.2
added 47 packages from 58 contributors and audited 47 packages in 2.641s
2 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
$ ls # 下載好套件後,會有新的檔案生成:package-lock.json, node_modules
index.js package-lock.json
node_modules package.json
然後就可以開始使用了!
]]>Node.js
下載 Node.js執行環境,讓 JavaScript 可以在瀏覽器之外的地方執行,網頁有 LTS 跟 current 兩個版本,LTS 為穩定版本,current 為最新版本,只要下載 LTS 版本即可。
安裝完成後,重新打開 Cmder(windows) 或 terminal(MacOs) 後:
$ node -v
v14.16.1 // 出現版本,安裝成功
npm 是 Node Package Manager 的縮寫,可以利用 Node 透過 npm 套件的安裝及管理。
$ npm install // 安裝 npm
//移動到專案底下
$ npm init // 會有初始設定,先按 enter 完成設定,而且會產生package.json 檔案
舉例:mathjs套件使用
$ npm install mathjs // 安裝 JavaScript 的數學套件
$ ls
package.json node_modules package-lock.json // 安裝完後,多了兩個檔案
//開一個新的 js 檔案
var math = require('mathjs') // 引用套件,並將 var 設為 math
console.log(math.sqrt(-4); // 類似 python 引用數據庫,就可以做 負數的開根號
package.json:紀錄套件
node_modules:從這個資料夾引用套件,通常會放在 .gitignore,因為有時使用的套件太多,放在 GitHub 會檔案太大,而且有 package.json 跟 package-lock.json 紀錄,所以當下載專案,執行 npm install
,把需要的套件載下來。
由 ES 和 lint 合成,lint 為語法檢查工具,ES 為 ECMAScript 簡稱,國際認定的標準語言規範,所以 ESLint 就是檢查 JavaScript 語法的工具。
$ npm install //安裝
...//安裝中
husky setting up git hooks // 在 git 內,執行 hook,在 commit 之前檢查語法。
... // 安裝完成
//編輯完 js 檔案,想要 commit:
$ git commit -m 'test'
✔ Preparing... // 語法檢查ing
✔ Hiding unstaged changes to partially staged files...
⚠ Running tasks...
]]>Node.js
下載 Node.js執行環境,讓 JavaScript 可以在瀏覽器之外的地方執行,網頁有 LTS 跟 current 兩個版本,LTS 為穩定版本,current 為最新版本,只要下載 LTS 版本即可。
安裝完成後,重新打開 Cmder(windows) 或 terminal(MacOs) 後:
$ node -v
v14.16.1 // 出現版本,安裝成功
npm 是 Node Package Manager 的縮寫,可以利用 Node 透過 npm 套件的安裝及管理。
$ npm install // 安裝 npm
//移動到專案底下
$ npm init // 會有初始設定,先按 enter 完成設定,而且會產生package.json 檔案
舉例:mathjs套件使用
$ npm install mathjs // 安裝 JavaScript 的數學套件
$ ls
package.json node_modules package-lock.json // 安裝完後,多了兩個檔案
//開一個新的 js 檔案
var math = require('mathjs') // 引用套件,並將 var 設為 math
console.log(math.sqrt(-4); // 類似 python 引用數據庫,就可以做 負數的開根號
package.json:紀錄套件
node_modules:從這個資料夾引用套件,通常會放在 .gitignore,因為有時使用的套件太多,放在 GitHub 會檔案太大,而且有 package.json 跟 package-lock.json 紀錄,所以當下載專案,執行 npm install
,把需要的套件載下來。
由 ES 和 lint 合成,lint 為語法檢查工具,ES 為 ECMAScript 簡稱,國際認定的標準語言規範,所以 ESLint 就是檢查 JavaScript 語法的工具。
$ npm install //安裝
...//安裝中
husky setting up git hooks // 在 git 內,執行 hook,在 commit 之前檢查語法。
... // 安裝完成
//編輯完 js 檔案,想要 commit:
$ git commit -m 'test'
✔ Preparing... // 語法檢查ing
✔ Hiding unstaged changes to partially staged files...
⚠ Running tasks...
]]>