Express是基于Node.js的前端Web開發(fā)框架, 其支持友好的API服務(wù),因此我們可以借助Express來模擬API數(shù)據(jù)進(jìn)行開發(fā)調(diào)試。
安裝
查看Node.js的版本
node -v
如果沒有安裝則先安裝 可參考:安裝Node.js 的Node安裝部分創(chuàng)建一個(gè)測(cè)試工程目錄,存放Express項(xiàng)目框架
npm install express-generator -g
如果連接不上或速度慢可切回國(guó)內(nèi)
npm install -g cnpm --registry=https://registry.npm.taobao.org
再執(zhí)行
cnpm install express-generator -g
如果創(chuàng)建成功會(huì)出現(xiàn)目錄位置如:
link /usr/local/bin/express@ -> /usr/local/lib/node_modules/express-generator/bin/express
3 接著就cd到你自己的路徑 執(zhí)行生產(chǎn)自己工程的目錄
express myApp
后提示警告并選擇繼續(xù)
warning: the default view engine will not be jade in future releases
warning: use --view=jade or --help for additional options
destination is not empty, continue? [y/N] y
之后會(huì)有一個(gè)列表等待安裝
npm install
來安裝上這些內(nèi)容析桥,工程中會(huì)多一個(gè)node_modules的文件夾,里面是所有依賴包文件。
4 Express模板中的文件庶喜,其中bin文件夾下面的www.js文件是服務(wù)的啟動(dòng)文件,其中啟動(dòng)了HTTP的服務(wù)救鲤,默認(rèn)端口為3000久窟。routes文件夾下面的文件用于配置api路由,默認(rèn)有index.js與users.js兩個(gè)本缠。app.js文件中對(duì)api進(jìn)行了初始化與配置斥扛。可以在users.js中添加一個(gè)測(cè)試api如下:
var express = require('express');
var router = express.Router();
/* 這個(gè)是默認(rèn)生成的. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
/* 添加一個(gè)測(cè)試api*/
router.get('/testAPi',function(rep,res,next){
res.send('{name:jaki,age:24}');
});
module.exports = router;
5 cd到自己工程目錄下丹锹,通過Node啟動(dòng)Express 執(zhí)行:node bin/www
, 或者也可以通過:DEBUG=myappName npm start
來啟動(dòng)稀颁。如果服務(wù)啟動(dòng)成功就可以在瀏覽器輸入http://127.0.0.1:3000/users/testAPi 會(huì)返回我們send()方法傳遞的字符串
6 如果要取消
MacOS系統(tǒng)在服務(wù)進(jìn)行中,可以使用control+c來釋放端口的監(jiān)聽楣黍,如果不小心使用control+z或者關(guān)閉了終端匾灶,會(huì)導(dǎo)致所監(jiān)聽端口的無法釋放,下次如果再次啟動(dòng)node服務(wù)租漂,會(huì)報(bào)Port 3000 is already in use的錯(cuò)誤阶女,可以使用如下方法來進(jìn)行所監(jiān)聽端口的釋放。首先使用如下命令查看所有監(jiān)聽某個(gè)端口的服務(wù)哩治,例如3000端口:
sudo lsof -i:3000
會(huì)列出當(dāng)前的進(jìn)程信息:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 9184 ucsapp 13u IPv6 0xd256c96f6cc1477d 0t0 TCP *:hbci (LISTEN)
在執(zhí)行殺死這個(gè)監(jiān)聽:sudo kill -9 9184
支持HTTPS
搭建HTTPS服務(wù)需要有證書憑證张肾,兩種證書我們可以選擇,一種是CA機(jī)構(gòu)簽發(fā)的證書锚扎,還有一種是我們自己制作的自簽名證書.現(xiàn)在創(chuàng)建自簽名證書吞瞪,這里提供兩種方法,測(cè)試第二種網(wǎng)頁(yè)在信任完證書后可以正常訪問:
方法一:
1 在Mac電腦上打開鑰匙串訪問應(yīng)用驾孔,打開其中的證書助理
證書的名字自定義芍秆,身份類型選擇的是
自簽名的根證書
惯疙,證書類型選擇SSL服務(wù)器
,之后點(diǎn)擊創(chuàng)建即可完成證書的創(chuàng)建妖啥。
2 從KeyChain中導(dǎo)出.p12文件并設(shè)置密碼霉颠,那這個(gè).p12文件其實(shí)是一個(gè)復(fù)合文件,其中包裝了私鑰與證書信息荆虱,使用OpenSSL工具可以將其中的信息進(jìn)行提取蒿偎,而搭建一個(gè)支持HTTPS的服務(wù)器是需要兩個(gè)文件,分別問證書文件和私鑰文件怀读,下面我們來從.p12文件中提取這些需要的文件诉位。
3 從p12中提取證書和私鑰 分別是導(dǎo)出密鑰和證書對(duì)應(yīng)nocerts nokeys,openssl導(dǎo)出過程中可能需要輸入密碼。
openssl pkcs12 -in yourP12Path.p12 -nocerts -out yourPathOfPrivateKey.pem -nodes
openssl pkcs12 -in yourP12Path.p12 -nokeys -out yourPathOfCert.pem -nodes
方法二:
1. openssl genrsa -des3 -out server.key 2048
2. openssl req -new -key server.key -out server.csr
3. cp /Users/xxx/Desktop/server.key server.key.org
openssl rsa -in server.key.org -out serverNew.key
4. openssl x509 -req -days 365 -in /Users/xxx/Desktop/server.csr -signkey /Users/xxx/Desktop/serverNew.key -out serverFinal.crt
4 將他們拷貝到你Express項(xiàng)目的bin文件夾下
5 在啟動(dòng)入口處即/bin/www文件里錄入一下代碼支持HTTPS
/*
HTTPS
*/
var fs = require('fs');
var https = require('https');
/*
密鑰文件
*/
var privatekey = fs.readFileSync('bin/privateKey.pem', 'utf8');
/*
證書文件
*/
var certificate = fs.readFileSync('bin/cert.pem', 'utf8');
var options={key:privatekey, cert:certificate};
var serverHttps = https.createServer(options, app);
/*
綁定端口
*/
serverHttps.listen(8080,function () {
console.log('Https server listening on port ' + 8080);
});
6 node bin/www 啟動(dòng)并瀏覽器輸入https://localhost:8080/users 因?yàn)槲覀兏淖兞吮O(jiān)聽端口為8080菜枷,因?yàn)橹С至薶ttps所以不再是http 接下來瀏覽器就會(huì)提示你是否信任該自簽名的證書苍糠。就算成功告一段落了。
7 付費(fèi)從CA機(jī)構(gòu)簽發(fā)的證書是被默認(rèn)信任的啤誊,則iOS工程無需做任何修改岳瞭,只需將請(qǐng)求url改成https,像上面這種我們自簽名的證書是會(huì)被默認(rèn)拒絕訪問蚊锹,xCode會(huì)輸出錯(cuò)誤提示:NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
瞳筏,。你可以調(diào)用試試看:
-(void)checkThisHttps{
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
8 如果改成http 監(jiān)聽3000 后又發(fā)現(xiàn)xcode限制了http的訪問牡昆,但我們可以通過設(shè)置NSAppTransportSecurity來繞過乏矾,其中NSAllowsArbitraryLoads是否允許所有不安全的請(qǐng)求,比如之一的http請(qǐng)求迁杨,默認(rèn)為NO钻心,因而我們又發(fā)現(xiàn)其下有一個(gè)NSExceptionDomains,里面有一個(gè)NSExceptionAllowsInsecureHTTPLoads铅协,設(shè)置是否允許此域名使用自簽名的證書進(jìn)行請(qǐng)求捷沸,默認(rèn)為NO,如果設(shè)置為YES狐史,則在提交時(shí)需要說明原因痒给。最好服務(wù)器都換成HTTPS協(xié)議的其實(shí)CA購(gòu)買的那種證書免去信任驗(yàn)證問題,不然只能適配驗(yàn)證自簽名的HTTPS證書了骏全。
9 在進(jìn)行HTTPS請(qǐng)求時(shí)苍柏,服務(wù)器會(huì)將證書文件返回給客戶端,如果客戶端的證書信任列表中有這個(gè)證書姜贡,則此請(qǐng)求可以正常進(jìn)行试吁,否則請(qǐng)求會(huì)被拒。因此,因此我們只需要將自簽名的證書安裝進(jìn)客戶端的信任列表就可以了熄捍。iOS中需要使用的證書是der格式烛恤,所以我們將pem格式的證書轉(zhuǎn)換成der格式的證書:
openssl x509 -inform PEM -in cert.pem -outform DER -out cert.der
然后將cert.der導(dǎo)入到iOS工程中,并設(shè)置NSURLSession的delegate為self后在回調(diào)用設(shè)置這個(gè)服務(wù)器中的證書文件對(duì)應(yīng)的der證書為可信任就行了余耽。自此HTTPS自簽名證書在iOS的應(yīng)用中就解決了缚柏,其實(shí)整個(gè)配置過程就是瀏覽器中選擇信任該證書的代碼體現(xiàn)而已。
-(void)normalHttps{
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://localhost:8080/users"]];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@,%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding],error);
}] resume];
}
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
NSLog(@"證書認(rèn)證");
//先判斷證書是否有效
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
//證書驗(yàn)證請(qǐng)求
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
/**
* 導(dǎo)入多張CA證書(Certification Authority碟贾,支持SSL證書以及自簽名的CA)
*/
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cert" ofType:@"der"];//自簽名證書
NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
if(!caCert) return;//讀取證書文件失敗
//可以添加多張證書
NSArray *caArray = @[caCert];
//驗(yàn)證規(guī)則
NSMutableArray *policies = [NSMutableArray array];
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//進(jìn)行自簽名證書的添加
for (NSData *certificateData in caArray) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
SecTrustResultType result = -1;
//通過本地導(dǎo)入的證書來驗(yàn)證服務(wù)器的證書是否可信
SecTrustEvaluate(serverTrust, &result);
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
return [[challenge sender] useCredential: credential forAuthenticationChallenge: challenge];
}
}