【node进阶】深度解析express框架---编写接口|解决跨域问题
? 作者簡介:一名普通本科大三的學(xué)生,致力于提高前端開發(fā)能力
? 個(gè)人主頁:前端小白在前進(jìn)的主頁
🔥 系列專欄 : node.js學(xué)習(xí)專欄
?? 個(gè)人社區(qū) : 個(gè)人交流社區(qū)
🍀 學(xué)習(xí)格言: ?? 打不倒你的會(huì)使你更強(qiáng)!??
🔥前言
我們?cè)谧銮昂蠖朔蛛x項(xiàng)目的時(shí)候,我們經(jīng)常調(diào)用后端所給我們的接口,從而獲取接口中的信息,這一篇文章將帶領(lǐng)大家做自己的后端,給大家講解怎么去運(yùn)用node給自己寫接口,同時(shí)幫助大家解決經(jīng)常遇到的跨域問題
📃目錄
- 學(xué)前先知:req.body | req.query | req.params
- req.body
- req.query
- req.params
- 使用express編寫接口
- 跨域問題
- 什么是跨域
- 為什么會(huì)產(chǎn)生跨域問題
- 解決跨域的兩種方案
- 1. CORS 解決跨域
- 什么是 CORS
- 使用 cors 中間件解決跨域問題
- cors的三個(gè)響應(yīng)頭
- Access-Control-Allow-Origin
- Access-Control-Allow-Headers
- Access-Control-Allow-Methods
- CORS請(qǐng)求的分類
- 簡單請(qǐng)求
- 預(yù)檢請(qǐng)求
- 簡單請(qǐng)求與預(yù)檢請(qǐng)求的區(qū)別
- 2. jsonp解決跨域
- jsonp的概念
- jsonp的原理
- 創(chuàng)建 JSONP 接口的注意事項(xiàng)
- 實(shí)現(xiàn)jsonp接口的步驟
- 小結(jié)
學(xué)前先知:req.body | req.query | req.params
想要從web的后臺(tái)中獲取接口的數(shù)據(jù),傳參是必不可少的,后臺(tái)想要接收前臺(tái)傳來的數(shù)據(jù)需要借助一些內(nèi)置的方法:
req.body
在express框架中,用req.body接收post客戶端的數(shù)據(jù),該屬性主要用于post()方法時(shí)傳遞參數(shù)使用,用法最廣泛,在你想使用這個(gè)方法的時(shí)候必須要導(dǎo)入第三方中間件body-parser.
演示代碼:
const express = require('express') const app = express() const body_parser = require('body-parser') app.use(body_parser.urlencoded({extended : false})) app.post('/user',(req,res)=>{console.log(req.body); //[Object: null prototype] { name: 'james', age: '37', gender: '男' }res.send('ok') })app.listen(80,()=>{console.log('http://127.0.0.1'); })這里使用了postman測(cè)試工具,打印出來的req.body為前臺(tái)傳給后臺(tái)的參數(shù),后臺(tái)告訴了前臺(tái)接收到了參數(shù),打印了ok
req.query
req.query用來獲取get方法傳遞的參數(shù),在這里就無需載入中間件了。
演示代碼:
const express = require('express');const app = express(); // 測(cè)試地址:http://127.0.0.1/user/?name=jamesapp.get('/user', function(req, res){let param = req.query.name; console.log(param) //jamesres.send('ok'); }); app.listen(80,()=>{console.log('http://127.0.0.1'); })在postman中測(cè)試地址為http://127.0.0.1?name=james,通過req.query取到了一個(gè)對(duì)象{name : 'james'},隨后拿到name屬性即可
req.params
有時(shí)候我們遇到的地址欄可能會(huì)是這種形式:http://127.0.0.1/user/1,這時(shí)候就需要我們的req.params去接收前臺(tái)傳來的參數(shù)
演示代碼:
const express = require('express') const app = express()app.get('/user/:id', function(req, res){let param = req.params.id; //1console.log(param)res.send('ok'); }); app.listen(80,()=>{console.log('http://127.0.0.1'); })在postman中自創(chuàng)地址http://127.0.0.1/user/1,通過req.query獲取到一個(gè)對(duì)象{id:1},隨后取出對(duì)象中的屬性即可
使用express編寫接口
-
創(chuàng)建基本的服務(wù)器
const express = require('express') //創(chuàng)建express實(shí)例 const app = express() //在這里寫下你的業(yè)務(wù)代碼...//調(diào)用app.listen 方法,指定端口號(hào)并啟動(dòng)web服務(wù)器 app.listen('80',()=>{console.log('http://127.0.0.1'); }) -
創(chuàng)建api路由模塊
const express = require('express') const apiRouter = express.Router() //在這里寫下你所創(chuàng)建的路由...//將apiRouter導(dǎo)出為一個(gè)模塊 module.exports = apiRouter -
將模塊導(dǎo)入創(chuàng)建基本服務(wù)的文件中
const express = require('express')const app = express() const apiRouter = require('./16.apiRouter') app.use('/api',apiRouter) app.listen('80',()=>{console.log('http://127.0.0.1'); }) -
編寫get接口
apiRouter.get('/get',(req,res)=>{// 通過 req.query 獲取客戶端通過查詢字符串,發(fā)送到服務(wù)器的數(shù)據(jù)const query = req.query// 調(diào)用 res.send() 方法,向客戶端響應(yīng)處理的結(jié)果res.send({status : 0, // 0 表示處理成功,1 表示處理失敗msg : 'GET請(qǐng)求成功!', // 狀態(tài)的描述data : query // 需要響應(yīng)給客戶端的數(shù)據(jù)}) }) -
編寫post接口
apiRouter.post('/post',(req,res)=>{// 通過 req.body 獲取請(qǐng)求體中包含的 url-encoded 格式的數(shù)據(jù)const body = req.body// 調(diào)用 res.send() 方法,向客戶端響應(yīng)結(jié)果res.send({status : 0, msg : 'post請(qǐng)求成功!',data : body}) })注意:如果要獲取 URL-encoded 格式的請(qǐng)求體數(shù)據(jù),須配置中間件:app.use(express.urlencoded({ extended: false }))
-
編寫delete接口
// 定義 DELETE 接口 apiRouter.delete('/delete', (req, res) => {res.send({status: 0,msg: 'DELETE請(qǐng)求成功',})})
跨域問題
什么是跨域
我們剛才編寫的接口,存在一個(gè)很嚴(yán)重的問題:不支持跨域請(qǐng)求。那么什么是跨域(CORS)呢?
當(dāng)一個(gè)請(qǐng)求url的協(xié)議、域名、端口號(hào)三者之間任意一個(gè)與當(dāng)前頁面url不同即為跨域.
舉個(gè)例子:我當(dāng)前的url為:http://127.0.0.1/user,但是我想訪問url為https://127.0.0.1/admin中的數(shù)據(jù),我能訪問的到嗎?顯然是不可能的,這就產(chǎn)生了跨域問題!
為什么會(huì)產(chǎn)生跨域問題
出于瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響。
可以說Web是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。同源策略會(huì)阻止一個(gè)域的javascript腳本和另外一個(gè)域的內(nèi)容進(jìn)行交互。
所謂同源(即指在同一個(gè)域)就是兩個(gè)頁面具有相同的協(xié)議(protocol),主機(jī)(host)和端口號(hào)(port)
解決跨域的兩種方案
1. CORS 解決跨域
什么是 CORS
CORS (Cross-Origin Resource Sharing,跨域資源共享)由一系列HTTP 響應(yīng)頭組成,這些 HTTP 響應(yīng)頭決定瀏覽器是否阻止前端 JS 代碼跨域獲取資源。
瀏覽器的同源安全策略默認(rèn)會(huì)阻止網(wǎng)頁“跨域”獲取資源。但如果接口服務(wù)器配置了 CORS 相關(guān)的 HTTP 響應(yīng)頭,就可以解除瀏覽器端的跨域訪問限制。
上圖中,如果我們網(wǎng)頁對(duì)服務(wù)器發(fā)送了跨域請(qǐng)求,服務(wù)器受到請(qǐng)求后返回書記,但是在返回的時(shí)候,瀏覽器的同源策略安全機(jī)制攔截了響應(yīng)的數(shù)據(jù),這就導(dǎo)致了跨域。
上圖中,使用cors后,配置了響應(yīng)頭Access-Control-Allow-*,這樣的話解除了瀏覽器對(duì)響應(yīng)的攔截,也就是解除了跨域。
注意:
CORS 主要在服務(wù)器端進(jìn)行配置。客戶端瀏覽器無須做任何額外的配置,即可請(qǐng)求開啟了 CORS 的接口。
CORS 在瀏覽器中有兼容性。只有支持XMLHttpRequest Level2 的瀏覽器,才能正常訪問開啟了 CORS 的服務(wù)端接口(例如:IE10+、Chrome4+、FireFox3.5+)。
使用 cors 中間件解決跨域問題
cors 是 Express 的一個(gè)第三方中間件。通過安裝和配置 cors 中間件,可以很方便地解決跨域問題。
使用步驟分為如下 3 步:
代碼示例:
const express = require('express')const app = express() app.use(express.urlencoded({extended : false}))//一定要在路由之前,配置cors 這個(gè)中間件,從而解決接口跨域問題 const cors = require('cors') app.use(cors()) //將上方的apiRouter模塊導(dǎo)入進(jìn)來 const apiRouter = require('./16.apiRouter') //訪問加上前綴 app.use('/api',apiRouter) app.listen('80',()=>{console.log('http://127.0.0.1'); })cors的三個(gè)響應(yīng)頭
Access-Control-Allow-Origin
響應(yīng)頭部中可以攜帶一個(gè) Access-Control-Allow-Origin 字段,其語法如下:
Access-Control-Allow-Origin : <origin> | *其中,origin 參數(shù)的值指定了允許訪問該資源的外域 URL。
如果指定了 Access-Control-Allow-Origin 字段的值為通配符 *,表示允許來自任何域的請(qǐng)求。
例如,下面的兩個(gè)字段值將分別允許來自 http://127.0.0.1/user 和任何url的請(qǐng)求:
Access-Control-Allow-Headers
默認(rèn)情況下,CORS 僅支持客戶端向服務(wù)器發(fā)送如下的 9 個(gè)請(qǐng)求頭:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值僅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
如果客戶端向服務(wù)器發(fā)送了額外的請(qǐng)求頭信息,則需要在服務(wù)器端,通過 Access-Control-Allow-Headers 對(duì)額外的請(qǐng)求頭進(jìn)行聲明,否則這次請(qǐng)求會(huì)失敗!
該設(shè)置的目的是:允許客戶端額外向服務(wù)器發(fā)送 Content-Type 請(qǐng)求頭和X-Custom-Header 請(qǐng)求頭
注意:多個(gè)請(qǐng)求頭之間使用英文逗號(hào)隔開進(jìn)行分割。
Access-Control-Allow-Methods
默認(rèn)情況下,CORS 僅支持客戶端發(fā)起 GET、POST、HEAD 請(qǐng)求。
如果客戶端希望通過 PUT、DELETE 等方式請(qǐng)求服務(wù)器的資源,則需要在服務(wù)器端,通過 Access-Control-Alow-Methods來指明實(shí)際請(qǐng)求所允許使用的 HTTP 方法。
示例代碼如下:
//只允許 POST、GET、DELETE、HEAD 請(qǐng)求方法 res.setHeader('Access-Control-Allow-Methods','POST','GET','DELETE','HEAD') //允許所有的HTTP請(qǐng)求方法 res.setHeader('Access-Control-Allow-Methods','*')CORS請(qǐng)求的分類
客戶端在請(qǐng)求 CORS 接口時(shí),根據(jù)請(qǐng)求方式和請(qǐng)求頭的不同,可以將 CORS 的請(qǐng)求分為兩大類,分別是:簡單請(qǐng)求和預(yù)檢請(qǐng)求
簡單請(qǐng)求
同時(shí)滿足以下兩大條件的請(qǐng)求,就屬于簡單請(qǐng)求:
預(yù)檢請(qǐng)求
只要符合以下任何一個(gè)條件的請(qǐng)求,都需要進(jìn)行預(yù)檢請(qǐng)求:
在瀏覽器與服務(wù)器正式通信之前,瀏覽器會(huì)先發(fā)送 OPTION 請(qǐng)求進(jìn)行預(yù)檢,以獲知服務(wù)器是否允許該實(shí)際請(qǐng)求,所以這一次的 OPTION 請(qǐng)求稱為“預(yù)檢請(qǐng)求”。服務(wù)器成功響應(yīng)預(yù)檢請(qǐng)求后,才會(huì)發(fā)送真正的請(qǐng)求,并且攜帶真實(shí)數(shù)據(jù)。
簡單請(qǐng)求與預(yù)檢請(qǐng)求的區(qū)別
簡單請(qǐng)求的特點(diǎn):客戶端與服務(wù)器之間只會(huì)發(fā)生一次請(qǐng)求。
預(yù)檢請(qǐng)求的特點(diǎn):客戶端與服務(wù)器之間會(huì)發(fā)生兩次請(qǐng)求,OPTION 預(yù)檢請(qǐng)求成功之后,才會(huì)發(fā)起真正的請(qǐng)求。
2. jsonp解決跨域
jsonp的概念
瀏覽器端通過 <script> 標(biāo)簽的 src (讓src)屬性,請(qǐng)求服務(wù)器上的數(shù)據(jù),同時(shí),服務(wù)器返回一個(gè)函數(shù)的調(diào)用。這種請(qǐng)求數(shù)據(jù)的方式叫做 JSONP。
注意:
jsonp的原理
動(dòng)態(tài)創(chuàng)建script標(biāo)簽,src屬性指向沒有跨域限制(重點(diǎn)!!!),指向一個(gè)接口,接口返回的格式一定是 ****() 函數(shù)表達(dá)式。
創(chuàng)建 JSONP 接口的注意事項(xiàng)
如果項(xiàng)目中已經(jīng)配置了 CORS 跨域資源共享,為了防止沖突,必須在配置 CORS 中間件之前聲明 JSONP 的接口。否則 JSONP 接口會(huì)被處理成開啟了 CORS 的接口。示例代碼如下:
// 必須在配置 cors 中間件之前,配置 JSONP 的接口【這個(gè)接口不會(huì)被處理成cors接口】 app.get('/api/jsonp', (req, res) => {...}) //一定要在路由之前,配置cors 這個(gè)中間件,從而解決接口跨域問題【后續(xù)的所有接口,都會(huì)被處理為 cors接口】 const cors = require('cors') app.use(cors())//在這里開啟了一個(gè) cors 的接口 app.get('api/get',(req,res)=>{...})實(shí)現(xiàn)jsonp接口的步驟
具體代碼如下:
app.get('/api/jsonp', (req, res) => {// TODO: 定義 JSONP 接口具體的實(shí)現(xiàn)過程// 1. 得到函數(shù)的名稱const funcName = req.query.callback// 2. 定義要發(fā)送到客戶端的數(shù)據(jù)對(duì)象const data = { name: 'zs', age: 22 ,req:req.query}// 3. 拼接出一個(gè)函數(shù)的調(diào)用const scriptStr = `${funcName}(${JSON.stringify(data)})`// 4. 把拼接的字符串,響應(yīng)給客戶端res.send(scriptStr)})隨后在網(wǎng)頁中發(fā)送jsonp請(qǐng)求即可,這里用的是$.ajax():
<button id="btnJSONP">JSONP</button> $('#btnJSONP').on('click', function () {$.ajax({type: 'GET',url: 'http://127.0.0.1/api/jsonp',dataType: 'jsonp',success: function (res) {console.log(res) //{ name: 'zs', age: 20 }},}) })小結(jié)
本篇的內(nèi)容主要就是針對(duì)express的接口編寫和解決跨域的,接口的編寫非常的容易上手,現(xiàn)階段并沒有到數(shù)據(jù)庫銜接,等后續(xù)文章更新數(shù)據(jù)庫之后,就可以真正做一個(gè)全棧開發(fā)者了,前端中,跨域的問題必須要會(huì),這里提供了最常用的cors解決跨域,jsonp在實(shí)際開發(fā)中使用較少,還有一種反向代理的方式,如果有機(jī)會(huì)更新vue的時(shí)候會(huì)詳細(xì)講解反向代理,好了,少年,繼續(xù)加油吧!😀😀
👑書寫不易,希望大家能夠給予三連支持,期待我更好的文章喲👑
總結(jié)
以上是生活随笔為你收集整理的【node进阶】深度解析express框架---编写接口|解决跨域问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深度学习环境配置5——windows下的
- 下一篇: 硬盘已删除的数据怎么恢复?磁盘数据恢复,