# CORS 中间件
const express = require ( 'express' ) const router = express. Router ( ) router. get ( '/get' , ( req, res ) => { res. send ( req. body) } ) router. get ( '/get' , ( req, res ) => { const query = req. query res. send ( { status : 200 , data : query, msg : 'GET请求成功' } ) } ) router. post ( '/post' , ( req, res ) => { const body = req. body res. send ( { status : 200 , data : body, msg : 'POST请求成功' } ) } ) module. exports = router
const express = require ( 'express' ) const router = require ( './router' ) const app = express ( ) app. use ( express. urlencoded ( { extended : false } ) ) const cors = require ( 'cors' ) app. use ( cors ( ) ) app. use ( '/api' , router) app. listen ( 8001 )
# CORS 的注意事项
CORS 主要在 服务器端 进行配置。客户端浏览器 无须做任何额外的配置 ,即可请求开启了 CORS 的接口。
CORS 在浏览器中 有兼容性 。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服
务端接口(例如: IE10+ 、 Chrome4+ 、 FireFox3.5+FireFox3.5+)
# CORS 响应头部
# Access Control Allow Origin
响应头部中可以携带一个 Access Control Allow Origin 字段,语法如下
Access- Control- Allow- Origin: < origin> | *
其中,origin 参数的值指定了 允许访问该资源的外域 URL 。
例如,下面的字段值将只允许 来自 https://nekoaimer.com
的请求
res. setHeader ( 'Access-Control-Allow-Origin' , 'https://nekoaimer.com' )
如果指定了 Access Control Allow Origin 字段的值为 通配符 **,表示允许来自任何域的请求,如下
res. setHeader ( 'Access-Control-Allow-Origin' , '*' )
默认情况下,CORS 仅 支持 客户端向服务器 发送如下的 9 个 请求头
Accept、 Accept Language 、 Content Language 、 DPR 、 Downlink 、 Save Data 、 Viewport Width 、 Width 、Content Type (值仅限于 text/plain 、 multipart/form data 、 application/x www form urlencoded 三者之一)
如果客户端向服务器发送了额外的请求头信息 ,则需要在 服务器端 ,通过 Access Control Allow Headers 对额外的请求头进行声明 ,否则这次请求会失败
res. setHeader ( 'Access-Control-Allow-Headers' , 'Content-Type, X-Custom-Header' )
# Access Control Allow Methods
默认情况下,CORS 仅支持客户端发起 GET 、 POST 、 HEAD 请求。
如果客户端希望通过 PUT 、 DELETE
等方式请求服务器的资源,则需要在服务器端,通过 Access Control Alow Methods
来 指明实际请求所允许使用的 HTTP 方法
res. setHeader ( 'Access-Control-Allow-Methods' , 'POST, GET, DELETE, HEAD' ) res. setHeader ( 'Access-Control-Allow-Methods' , '*' )
# CORS 请求分类
# 简单请求
同时满足以下两大条件的请求,就属于简单请求:
请求方式 GET 、 POST 、 HEAD 三者之一
HTTP 头部信息 不超过以下几种字段: 无自定义头部字段 、 Accept 、 Accept Language 、 Content Language 、 DPR 、Downlink 、 Save Data 、 Viewport Width 、 Width 、 Content Type (只有三个值 application/x www form、urlencoded 、 multipart/form data 、 text/plain
# 预检请求
只要符合以下任何一个条件的请求,都需要进行预检请求:
请求方式为 GET 、 POST 、 HEAD 之外的请求 Method 类型
请求头中 包含自定义头部字段
向服务器发送 了 application/json 格式的数据
在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求 ,所以这一次的 OPTION 请求称为 “预检请求”。 服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据 。
# 请求区别
简单请求的特点:客户端与服务器之间 只会发生一次请求 。
预检请求的特点:客户端与服务器之间会发生两次请求 OPTION 预检请求成功之后,才会发起真正的请求 。
# JSONP 概念与特点
app. get ( '/api/jsonp' , ( req, res ) => { } ) app. use ( cors ( ) ) app. get ( '/api/get' , ( req, res ) => { } )
# JSONP 接口实现步骤
获取客户端发送过来的 回调函数的名字
得到要通过 JSONP 形式 发送给客户端的数据
根据前两步得到的数据, 拼接出一个函数调用的字符串
把上一步拼接得到的字符串,响应给客户端的 <script>
app. get ( '/api/jsonp' , ( req, res ) => { const funcName = req. query. callback const data = { name : 'saber' , age : 16 } const scriptStr = ` ${ funcName} ( ${ JSON . stringify ( data) } ) ` res. send ( scriptStr) } )
# GET/POST/JSONP 测试
# router.js
const express = require ( 'express' ) const router = express. Router ( ) router. get ( '/get' , ( req, res ) => { res. send ( { status : 200 , data : req. query, msg : 'GET请求成功' } ) } ) router. post ( '/post' , ( req, res ) => { res. send ( { status : 200 , data : req. body, msg : 'POST请求成功' } ) } ) router. delete ( '/delete' , ( req, res ) => { res. send ( { status : 200 , data : req. body, msg : 'DELETE请求成功' } ) } ) module. exports = router
# index,js
const express = require ( 'express' ) const router = require ( './router' ) const app = express ( ) app. use ( express. urlencoded ( { extended : false } ) ) app. get ( '/api/jsonp' , ( req, res ) => { const funcName = req. query. callback const data = { name : 'saber' , age : 16 } const scriptStr = ` ${ funcName} ( ${ JSON . stringify ( data) } ) ` console. log ( scriptStr) ; res. send ( scriptStr) } ) const cors = require ( 'cors' ) app. use ( cors ( ) ) app. use ( '/api' , router) app. listen ( 8001 )
# index.html
<! DOCTYPE html > < html lang = " en" > < head> < meta charset = " UTF-8" > < meta http-equiv = " X-UA-Compatible" content = " IE=edge" > < meta name = " viewport" content = " width=device-width, initial-scale=1.0" > < title> core-jsop</ title> < script src = " https://cdn.staticfile.org/jquery/1.10.0/jquery.js" > </ script> </ head> < body> < button id = " btnGET" > GET</ button> < button id = " btnPOST" > POST</ button> < button id = " btnDELETE" > DELETE</ button> < button id = " btnJSONP" > JSONP</ button> < script> $ ( function ( ) { $ ( '#btnGET' ) . on ( 'click' , function ( ) { $. ajax ( { type : 'GET' , url : 'http://127.0.0.1:8001/api/get' , data : { name : 'saber' , age : 16 , } , success ( res ) { console. log ( res) ; } } ) } ) $ ( '#btnPOST' ) . on ( 'click' , function ( ) { $. ajax ( { type : 'POST' , url : 'http://127.0.0.1:8001/api/post' , data : { name : 'saber' , age : 16 , } , success ( res ) { console. log ( res) ; } } ) } ) $ ( '#btnDELETE' ) . on ( 'click' , function ( ) { $. ajax ( { type : 'DELETE' , url : 'http://127.0.0.1:8001/api/delete' , data : { name : 'saber' , age : 16 , } , success ( res ) { console. log ( res) ; } } ) } ) $ ( '#btnJSONP' ) . on ( 'click' , function ( ) { $. ajax ( { type : 'JSONP' , url : 'http://127.0.0.1:8001/api/jsonp' , dataType : 'jsonp' , data : { name : 'saber' , age : 16 , } , success ( res ) { console. log ( success) ; } } ) } ) } ) </ script> </ body> </ html>