Express是基于Node.js的前端Web开发框架, 其支持友好的API服务,因此我们可以借助Express来模拟API数据进行开发调试。
安装
查看Node.js的版本
node -v
如果没有安装则先安装 可参考:安装Node.js 的Node安装部分创建一个测试工程目录,存放Express项目框架
npm install express-generator -g
如果连接不上或速度慢可切回国内
npm install -g cnpm --registry=https://registry.npm.taobao.org
再执行
cnpm install express-generator -g
如果创建成功会出现目录位置如:
link /usr/local/bin/express@ -> /usr/local/lib/node_modules/express-generator/bin/express
3 接着就cd到你自己的路径 执行生产自己工程的目录
express myApp
后提示警告并选择继续
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
之后会有一个列表等待安装
npm install
来安装上这些内容,工程中会多一个node_modules的文件夹,里面是所有依赖包文件。
4 Express模板中的文件,其中bin文件夹下面的www.js文件是服务的启动文件,其中启动了HTTP的服务,默认端口为3000。routes文件夹下面的文件用于配置api路由,默认有index.js与users.js两个。app.js文件中对api进行了初始化与配置。可以在users.js中添加一个测试api如下:
var express = require('express');
var router = express.Router();
/* 这个是默认生成的. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
/* 添加一个测试api*/
router.get('/testAPi',function(rep,res,next){
res.send('{name:jaki,age:24}');
});
module.exports = router;
5 cd到自己工程目录下,通过Node启动Express 执行:node bin/www
, 或者也可以通过:DEBUG=myappName npm start
来启动。如果服务启动成功就可以在浏览器输入http://127.0.0.1:3000/users/testAPi 会返回我们send()方法传递的字符串
6 如果要取消
MacOS系统在服务进行中,可以使用control+c来释放端口的监听,如果不小心使用control+z或者关闭了终端,会导致所监听端口的无法释放,下次如果再次启动node服务,会报Port 3000 is already in use的错误,可以使用如下方法来进行所监听端口的释放。首先使用如下命令查看所有监听某个端口的服务,例如3000端口:
sudo lsof -i:3000
会列出当前的进程信息:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 9184 ucsapp 13u IPv6 0xd256c96f6cc1477d 0t0 TCP *:hbci (LISTEN)
在执行杀死这个监听:sudo kill -9 9184
支持HTTPS
搭建HTTPS服务需要有证书凭证,两种证书我们可以选择,一种是CA机构签发的证书,还有一种是我们自己制作的自签名证书.现在创建自签名证书,这里提供两种方法,测试第二种网页在信任完证书后可以正常访问:
方法一:
1 在Mac电脑上打开钥匙串访问应用,打开其中的证书助理
证书的名字自定义,身份类型选择的是
自签名的根证书
,证书类型选择
SSL服务器
,之后点击创建即可完成证书的创建。
2 从KeyChain中导出.p12文件并设置密码,那这个.p12文件其实是一个复合文件,其中包装了私钥与证书信息,使用OpenSSL工具可以将其中的信息进行提取,而搭建一个支持HTTPS的服务器是需要两个文件,分别问证书文件和私钥文件,下面我们来从.p12文件中提取这些需要的文件。
3 从p12中提取证书和私钥 分别是导出密钥和证书对应nocerts nokeys,openssl导出过程中可能需要输入密码。
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项目的bin文件夹下
5 在启动入口处即/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 启动并浏览器输入https://localhost:8080/users 因为我们改变了监听端口为8080,因为支持了https所以不再是http 接下来浏览器就会提示你是否信任该自签名的证书。就算成功告一段落了。
7 付费从CA机构签发的证书是被默认信任的,则iOS工程无需做任何修改,只需将请求url改成https,像上面这种我们自签名的证书是会被默认拒绝访问,xCode会输出错误提示:NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
,。你可以调用试试看:
-(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 监听3000 后又发现xcode限制了http的访问,但我们可以通过设置NSAppTransportSecurity来绕过,其中NSAllowsArbitraryLoads是否允许所有不安全的请求,比如之一的http请求,默认为NO,因而我们又发现其下有一个NSExceptionDomains,里面有一个NSExceptionAllowsInsecureHTTPLoads,设置是否允许此域名使用自签名的证书进行请求,默认为NO,如果设置为YES,则在提交时需要说明原因。最好服务器都换成HTTPS协议的其实CA购买的那种证书免去信任验证问题,不然只能适配验证自签名的HTTPS证书了。
9 在进行HTTPS请求时,服务器会将证书文件返回给客户端,如果客户端的证书信任列表中有这个证书,则此请求可以正常进行,否则请求会被拒。因此,因此我们只需要将自签名的证书安装进客户端的信任列表就可以了。iOS中需要使用的证书是der格式,所以我们将pem格式的证书转换成der格式的证书:
openssl x509 -inform PEM -in cert.pem -outform DER -out cert.der
然后将cert.der导入到iOS工程中,并设置NSURLSession的delegate为self后在回调用设置这个服务器中的证书文件对应的der证书为可信任就行了。自此HTTPS自签名证书在iOS的应用中就解决了,其实整个配置过程就是浏览器中选择信任该证书的代码体现而已。
-(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(@"证书认证");
//先判断证书是否有效
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
//证书验证请求
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
/**
* 导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA)
*/
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"cert" ofType:@"der"];//自签名证书
NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
if(!caCert) return;//读取证书文件失败
//可以添加多张证书
NSArray *caArray = @[caCert];
//验证规则
NSMutableArray *policies = [NSMutableArray array];
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
NSMutableArray *pinnedCertificates = [NSMutableArray array];
//进行自签名证书的添加
for (NSData *certificateData in caArray) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
SecTrustResultType result = -1;
//通过本地导入的证书来验证服务器的证书是否可信
SecTrustEvaluate(serverTrust, &result);
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
return [[challenge sender] useCredential: credential forAuthenticationChallenge: challenge];
}
}