Nginx upstream 相关配置
Nginx_upstream实现:设置备份主机及过滤HTTP错误自动切除[8000=>Node服务器 || 2000=>默认错误处理页]:
- #集群中的所有后台服务器的配置信息
- upstream nodeJs {
- #server 123.56.233.208 weight=10;
- #server 127.0.0.1:3000 weight=10;
- server 127.0.0.1:8000;
- server 127.0.0.1:2000 backup;
- }
- #调用所有的Server配置文件
- include /usr/local/nginx/conf/vhosts/*.conf;
- server {
- listen 3000;
- server_name liuxinxiu.com;
- add_header Proxy-By $upstream_http_server; #代理服务器Server
- location / {
- proxy_pass http://nodeJs; #反向代理到后端Server
- proxy_set_header Host $host:3000;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- #proxy_next_upstream error timeout invalid_header http_403 http_404;
- }
- }
Nginx=>2000端口默认错误处理页(相关配置):
- server{
- listen 2000;
- server_name 127.0.0.1;
- index index.html index.htm index.php;
- root /ftp/www/2000;
- error_page 404 /index.html;
- }
关于setTimeout传参的思考
- function countdown(n){
- //var i=10;if(!n)n=i;
- function _show(o){
- return function(){
- countdown(o);
- }
- }
- if(n>0){
- console.log(n);n--;
- setTimeout(_show(n),1000);
- }
- };countdown(10);
CORS||跨域资源共享||NodeJs版本实现
使用NodeJs实现CORS 跨域资源共享,可传参origin通过限制,代码如下:
- var http=require('http');
- var origin=require('./origin'); //调用白名单列表
- function CORS_Node(){
- this.exec=function(route,req,res){
- var _self=this;
- /************** 获取客户端origin的域名 **************/
- origin.req=req; //白名单设置置请求头
- origin.yes=origin.listV(); //是否在名单|true
- origin.name=origin.getName(); //客户端ORIGIN
- /******** 先纠正参数,参数正确后匹配白名单 ********/
- /********** 判断是GET请求类型 **********/
- if(req.method.toUpperCase()=="GET"){
- var params=[];
- //params=url.parse(request.url,true).query;
- //params['fruit']=compute(params);
- res.writeHeader(200,{
- "Content-type":"text/html; charset=utf-8"
- });
- res.write('<h1>It is forbidden for the URL request!</h1>');
- res.write('<hr><address>NodeJs/'+process.version);
- res.write(' at '+req.headers.host.split(':')[0]);
- res.write(' Port '+req.headers.host.split(':')[1]+'</address>');
- res.end();
- }
- /********* 判断是POST请求类型 **********/
- else if(req.method.toUpperCase()=='POST'){
- var postData="";
- /********** 读取Post提交的数据 **********/
- req.addListener("data",function(data){
- postData+=data;
- });
- /********** 数据读取完毕就会执行的监听 *********/
- req.addListener("end",function(){
- /********* 定义Post请求主体 *********/
- var query=require('querystring').parse(postData);
- /********** 给客户端返回数据自造JSON **********/
- function getJson(status){
- if(isNaN(status))status=-1;
- else{status=Number(status)}
- var _drr='{'
- +'"status":"1",'
- +'"name":"'+query.name+'",'
- +'"gender":"'+query.gender+'"}';
- var _arr='{'
- +'"status":1,'
- +'"url":"http://www.liuxinxiu.com/",'
- +'"dataList":'
- +'{'
- +'"siteId":101,'
- +'"title":"我的博客||Node Server",'
- +'"images":"http://www.liuxinxiu.com/upload/2016/08/10/moren.gif",'
- +'"indexNum":"10",'
- +'"pageNum":"100000",'
- +'"tagNum":"22",'
- +'"linkType":"linkTaobao",'
- +'"publishTime":"23:15:30"'
- +'}'
- +'}';
- this._dr=JSON.parse(_drr);this._ar=JSON.parse(_arr);
- this._dt=this._dr;this._dt.getUser=this._ar;
- }
- var errStr={"status":-1,"info":"Request Error"};
- /********** 先初步设置头信息,跨域全放开稍后再进行匹配验证 **********/
- var content_type,content_length,
- content_type='application/json; charset=utf-8';
- content_length=Buffer.byteLength(res,'utf8');
- res.setHeader('Access-Control-Allow-Origin','*');
- res.setHeader('Access-Control-Allow-Headers','X-Requested-With');
- res.setHeader('Access-Control-Allow-Methods','GET,POST,PUT,DELETE,OPTIONS');
- res.setHeader('Content-Type',content_type);
- res.setHeader('Server','NodeJs/'+process.version);
- /************** 判断如果有POST过来规范的数据 *************/
- if(query.name&&query.gender){
- //调用数据
- getJson(1);
- /******** 匹配客户端域名是否在数组列表中 ******/
- //if(_self.in_array(origin,allow_origin)){
- if(origin.yes){
- res.setHeader('Access-Control-Allow-Origin',origin.name);
- res.end(JSON.stringify(_dt));
- }
- else{
- /******** 如有设置就取设置URL返回头信息 ********/
- if(query.origin){
- res.setHeader('Access-Control-Allow-Origin',query.origin);
- res.end(JSON.stringify(_dt));
- }
- /******** 没设置URL就返回无权限错误信息 ********/
- else{
- errStr.info="You don't have permission to submit!";
- res.setHeader('Access-Control-Allow-Origin',origin.name);
- res.end(JSON.stringify(errStr));
- }
- }
- }
- /********* 没有所匹配的POST提交数据||都要设头返回信息 ********/
- else{
- /******** 其他POST参数的提交 ********/
- if(query){
- res.writeHeader(res.statusCode,{
- "Access-Control-Allow-Origin":origin.name,
- "Access-Control-Allow-Headers":"X-Requested-With",
- "Access-Control-Allow-Methods":"GET,POST,PUT,DELETE,OPTIONS",
- "Content-type":"application/json; charset=utf-8"
- });
- var err={status:-1,info:"Syntax error in parameters or arguments."};
- res.end(JSON.stringify(err));
- }
- else{
- res.writeHeader(res.statusCode,{
- "Content-type": "text/html; charset=utf-8"
- });
- res.end('It is forbidden for the URL request!');
- }
- }
- /****** 判断结束 ******/
- });
- }
- /****** 内部结束 ******/
- }
- }
- module.exports=new CORS_Node();
NodeJs数据提交接口地址 (不允许使用GET访问) :http://liuxinxiu.com:3000/CORS_Node/
注意:NodeJs Server 是本站的测试环境,有时候因需要会临时关闭,该地址仅供测试,如您有需要请自建环境~
配合HTML代码如下:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
- <meta name="format-detection"content="telephone=no">
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-status-bar-style" content="black" />
- <style>body,html {background:#fff;font-family: "Lucida Grande",Calibri,Arial;font-size:12pt;color: #333;background: #f8f8f8;text-align:center;}*{margin:0;padding:0;}h1{line-height:1.6em;font-size:24px;text-indent:.5em;padding-top:.6em}i{line-height:2em;font-size:18px;color:#999;}.line{height:10px;border-bottom:1px solid #ccc;font-size:0;overflow:hidden;}</style>
- <title>跨域测试</title>
- </head>
- <body>
- <h1 id="show"></h1>
- <input type="button" value="Click me" onclick="msg()" />
- </body>
- <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
- <script type='text/javascript'>
- /********** 获取URL参数 **********/
- function getQueryString(name){
- var reg=new RegExp("(^|&)"+name+"=([^&]*)(&|$)","i");
- var r=window.location.search.substr(1).match(reg);
- if (r!=null) return unescape(r[2]); return null;
- }
- var _n=getQueryString('n');
- var _url=getQueryString('url');
- var _name=getQueryString('name');
- var _gender=getQueryString('gender');
- var _origin=getQueryString('origin');
- var _error=getQueryString('error');
- console.log('origin:'+_origin+' —— name:'+_name+' —— gender:'+_gender);
- window.onload=function(){
- if(_n=='php'){
- location.href='http://'
- +location.host
- +location.pathname
- +'?origin=http://'+location.host;
- }else if(_n=='node'){
- location.href='http://'
- +location.host
- +location.pathname
- +'?origin=http://'+location.host+'&'
- +'url=http://liuxinxiu.com:3000/CORS_Node/'
- }else if(_n=='proxy'){
- location.href='http://'
- +location.host
- +location.pathname
- +'?origin=http://'+location.host+'&'
- +'url=http://liuxinxiu.com:3000/CORS_Node_Proxy/'
- }else if(_n=='test'){
- location.href='http://test1.liuxinxiu.com/php/Interface/html/server.html'
- +'?origin=http://test1.liuxinxiu.com&'
- +'url=http://liuxinxiu.com:3000/CORS_Node_Proxy/&'
- +'error=1'
- }
- }
- /********** 发起Ajax请求 **********/
- function msg(){
- /******* 动态切换提交数据 *******/
- if(_origin&&!_error){
- if(_name&&_gender){
- var data={name:_name,gender:_gender,origin:_origin};
- }
- else{
- var data={name:"xiaoming",gender:"male",origin:_origin};
- }
- }
- else if(_error==null){
- var data={name:"xiaoming",gender:"male"};
- }
- else if(_error){
- var data={xxx:111};
- }
- /******* 动态设置提交URL *******/
- if(_url){
- var urlPath=_url;
- }
- else{
- var urlPath='http://code.liuxinxiu.com/php/Post/CORS_PHP.php';
- }
- $.ajax({
- type:'post',
- url:urlPath,
- data:data,
- cache:false,
- dataType:'json',
- success:function(data){
- if(data.name){
- document.getElementById("show").innerHTML=data.name+' '+data.gender;
- }
- else if(data.status!=1){
- document.getElementById("show").innerHTML=data.info;
- }
- },
- error:function(){
- console.log("请求错误//")
- }
- });
- };
- /***********************************************************************************************
- $.post("http://www.server.com/server.php",{name:"fdipzone",gender:"male"}).done(function(data){
- document.getElementById("show").innerHTML=data.name+' '+data.gender;
- });
- **********************************************************************************************/
- </script>
- </html>
HTML访问地址 (测试跨域) ==> http://test1.liuxinxiu.com/php/Interface/html/server.html?n=node
HTML访问地址 (非法参数) ==> http://test1.liuxinxiu.com/php/Interface/html/server.html?error=node
注意:本站的 NodeJs Server 是学习测试环境,有临时关闭的可能,建议在本地环境测试~
JS把数组类型转换为JSON对象或JSON字符串
- var a = ['a','b','c'];
- var json = {};
- for(var i=0;i<a.length;i++)
- {
- json[i]=a[i];
- }
- var jsonStr=JSON.stringify(json);//结果:"{'1':'a','2':'b','3':'c'}"
- var jsonObj=JSON.parse(jsonStr); //结果:[object Object]
JS Array To Json 加强版:
1. 自然数自动递增并设置K值
2. 取偶数Length为Json数组的K值
- /******** 获取客户端请求的header整体头部信息 ********/
- this.rawHeaders=function(state){
- var json={};
- if(!state){
- for(var i=0;i<req.rawHeaders.length;i++){
- var s,s=i;
- if(i%2==0){
- s++;json[req.rawHeaders[i]]=req.rawHeaders[s];
- }
- }
- }
- if(state){
- for(var i=0;i<req.rawHeaders.length;i++){
- json[i]=req.rawHeaders[i];
- }
- }
- var jsonStr=JSON.stringify(json);//结果:"{'1':'a','2':'b','3':'c'}"
- var jsonObj=JSON.parse(jsonStr); //结果:[object Object]
- return jsonObj;
- };
CORS||跨域资源共享||PHP版本实现
使用PHP实现CORS 跨域资源共享,可传参origin通过限制,代码如下:
- <?php
- /******** 定义Response返回header头格式及编码 ********/
- header('Content-type: application/json; charset=utf-8');
- /******** 回调参数设置 ********/
- $param="origin";
- $origin_URL=$_REQUEST[$param];
- /******** json_encode 转成=> encode_json *******/
- function encode_json($str){
- return urldecode(json_encode(url_encode($str)));
- }
- function url_encode($str){
- if(is_array($str)){
- foreach($str as $key=>$value){
- $str[urlencode($key)]=url_encode($value);
- }
- }else{
- $str=urlencode($str);
- }
- return $str;
- }
- /**************** \/\/反转义范例 ********************/
- function stripslashes_deep($value){
- $value=is_array($value)?
- array_map('stripslashes_deep',$value):
- stripslashes($value);
- return $value;
- }
- /******************** Example ******************************/
- $array=array("f\\'oo", "b\\'ar", array("fo\\'o", "b\\'ar"));
- $array=stripslashes_deep($array);
- /******************** Output *******************************/
- //echo encode_json(array('china'=>'钓鱼岛是中国的!','Japan'=>array('name'=>'日本狗!')));
- /************ 定义Post过来什么数据就返回什么数据 ***********/
- $res=array(
- 'status'=>-1,
- 'name'=>isset($_POST['name'])?$_POST['name']:'',
- 'gender'=>isset($_POST['gender'])?$_POST['gender']:''
- );
- $arr=array(
- "status"=>1,
- "url"=>"http://www.liuxinxiu.com/",
- "dataList"=>array(
- "siteId"=>"1",
- "title"=>urldecode('我的博客'),
- "images"=>"http://192.168.9.100/upload/2015/06/20/moren.gif",
- "indexNum"=>10,
- "pageNum"=>"300",
- "tagNum"=>"20",
- "linkType"=>"linkTaobao",
- "publishTime"=>"20:00:00"
- )
- );
- $arr['dataList']['images']="http://www.liuxinxiu.com/upload/2015/06/20/moren.gif";
- //print_r($arr);
- /*************** 定义错误信息 ***************/
- $errStr='{"status":-1,"info":"Request Error"}';
- $errJson=json_decode($errStr,true); //json_decode转成了array数组
- //print_r($errJson) //转成了array数组
- /************** 获取客户端的Origin域名 **************/
- $origin=isset($_SERVER['HTTP_ORIGIN'])?$_SERVER['HTTP_ORIGIN']:'';
- /******** 定义符合规则的域名数组 ********/
- $allow_origin=array(
- 'http://liuxinxiu.com',
- 'http://code.liuxinxiu.com',
- 'http://test.liuxinxiu.com'
- );
- /****************** 判断如果有POST过来数据 *********************/
- if(isset($_POST['name'])&&isset($_POST['gender'])){
- /********** 只要是POST请求过来无论合法与否都要正常通信 **********/
- header('Access-Control-Allow-Methods:POST');
- header('Access-Control-Allow-Headers:x-requested-with,content-type');
- /******** 匹配客户端域名是否在数组列表中 ******/
- if(in_array($origin,$allow_origin)){
- header('Access-Control-Allow-Origin:'.$origin);
- $res['status']=1;
- $res['getUser']=$arr;
- echo json_encode($res);
- }
- else if(!in_array($origin,$allow_origin)){
- /******** 如有设置就取设置URL返回头信息 ********/
- if(isset($origin_URL)){
- header('Access-Control-Allow-Origin:'.$origin_URL);
- $res['status']=1;
- $res['getUser']=$arr;
- echo encode_json($res);
- //echo json_encode("中文", JSON_UNESCAPED_UNICODE);
- }
- /******** 如没有设置URL就返回错误信息 ********/
- else{
- header('Access-Control-Allow-Origin:'.$origin);
- $errJson['status']=-1;
- $errJson['info']="You don't have permission to submit!";
- echo encode_json($errJson);
- }
- }
- }
- /************ 没有所匹配的POST提交数据 ***********/
- else{
- if($GLOBALS['HTTP_RAW_POST_DATA']){
- header('Access-Control-Allow-Origin:'.$origin);
- $errJson['status']=-1;
- $errJson['info']="Syntax error in parameters or arguments.";
- echo encode_json($errJson);
- }
- else{
- header("Content-type: text/html; charset=utf-8");
- echo 'It is forbidden for the URL request!';
- }
- }
- ?>
PHP数据提交接口地址 (禁止使用GET访问):http://code.liuxinxiu.com/php/Interface/server.php
配合HTML代码如下:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
- <meta name="format-detection"content="telephone=no">
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-status-bar-style" content="black" />
- <style>body,html {background:#fff;font-family: "Lucida Grande",Calibri,Arial;font-size:12pt;color: #333;background: #f8f8f8;text-align:center;}*{margin:0;padding:0;}h1{line-height:1.6em;font-size:24px;text-indent:.5em;padding-top:.6em}i{line-height:2em;font-size:18px;color:#999;}.line{height:10px;border-bottom:1px solid #ccc;font-size:0;overflow:hidden;}</style>
- <title>跨域测试</title>
- </head>
- <body>
- <h1 id="show"></h1>
- <input type="button" value="Click me" onclick="msg()" />
- </body>
- <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
- <script type='text/javascript'>
- /********** 获取URL参数 **********/
- function getQueryString(name){
- var reg=new RegExp("(^|&)"+name+"=([^&]*)(&|$)","i");
- var r=window.location.search.substr(1).match(reg);
- if (r!=null) return unescape(r[2]); return null;
- }
- /********** 发起Ajax请求 **********/
- function msg(){
- /******* 动态切换提交数据 *******/
- if(_origin){
- if(_name&&_gender){
- var data={name:_name,gender:_gender,origin:_origin};
- }
- else{
- var data={name:"xiaoming",gender:"male",origin:_origin};
- }
- }
- else if(_error==null){
- var data={name:"xiaoming",gender:"male"};
- }
- else if(_error){
- var data={xxx:111};
- }
- /******* 动态设置提交URL *******/
- if(_url){
- var urlPath=_url;
- }
- else{
- var urlPath='http://code.liuxinxiu.com/php/Interface/server.php';
- }
- $.ajax({
- type:'post',
- url:urlPath,
- data:data,
- cache:false,
- dataType:'json',
- success:function(data){
- if(data.name){
- document.getElementById("show").innerHTML=data.name+' '+data.gender;
- }
- else if(data.status!=1){
- document.getElementById("show").innerHTML=data.info;
- }
- },
- error:function(){
- console.log("请求错误//")
- }
- });
- };
- /***********************************************************************************************
- $.post("http://www.server.com/server.php",{name:"fdipzone",gender:"male"}).done(function(data){
- document.getElementById("show").innerHTML=data.name+' '+data.gender;
- });
- **********************************************************************************************/
- </script>
- </html>
HTML访问地址 (测试跨域) ==> http://test1.liuxinxiu.com/php/Interface/html/server.html?n=php
HTML访问地址 (非法参数) ==> http://test1.liuxinxiu.com/php/Interface/html/server.html?error=php
CORS||跨域资源共享 (Cross-origin resource sharing)
CORS是一个W3C标准,全称是"跨域资源共享" (Cross-origin resource sharing)
以往的解决方案
以前要实现跨域访问,可以通过JSONP、Flash或者服务器中转的方式来实现,但是现在我们有了CORS。
CORS与JSONP相比,无疑更为先进、方便和可靠。
1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS(这部分会在后文浏览器支持部分介绍)。
详细内容
要使用CORS,我们需要了解前端和服务器端的使用方法。
1、 前端
以前我们使用Ajax,代码类似于如下的方式:
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "/hfahe", true);
- xhr.send();
这里的“/hfahe”是本域的相对路径。
如果我们要使用CORS,相关Ajax代码可能如下所示:
- var xhr = new XMLHttpRequest();
- xhr.open("GET", "http://www.liuxinxiu.com/hfahe", true);
- xhr.send();
请注意,代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。
我们还必须提供浏览器回退功能检测和支持,避免浏览器不支持的情况。
- function createCORSRequest(method, url) {
- var xhr = new XMLHttpRequest();
- if ("withCredentials" in xhr) {
- // 此时即支持CORS的情况
- // 检查XMLHttpRequest对象是否有“withCredentials”属性
- // “withCredentials”仅存在于XMLHTTPRequest2对象里
- xhr.open(method, url, true);
- } else if (typeof!= "undefined") {
- // 否则检查是否支持XDomainRequest,IE8和IE9支持
- // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
- xhr = new XDomainRequest();
- xhr.open(method, url);
- } else {
- // 否则,浏览器不支持CORS
- xhr = null;
- }
- return xhr;
- }
- var xhr = createCORSRequest('GET', url);
- if (!xhr) {
- throw new Error('CORS not supported');
- }
现在如果直接使用上面的脚本进行请求,会看到浏览器里控制台的报错如下:
错误显示的很明显,这是因为我们还未设置Access-Control-Allow-Origin头。
2、 服务器
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
HTTP 头的设置方法有很多,http://enable-cors.org/这篇文章里对各种服务器和语言的设置都有详细的介绍,下面我们主要介绍Apache和PHP里的设置方法。
Apache:Apache需要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只需要在Apache配置文件的<Directory>, <Location>, <Files>或<VirtualHost>的配置里加入以下内容即可:
- Header set Access-Control-Allow-Origin *
PHP:只需要使用如下的代码设置即可。
- <?php
- header("Access-Control-Allow-Origin:*");
以上的配置的含义是允许任何域发起的请求都可以获取当前服务器的数据。当然,这样有很大的危险性,恶意站点可能通过XSS攻击我们的服务器。所以我们应该尽量有针对性的对限制安全的来源,例如下面的设置使得只有http://www.liuxinxiu.com 这个域才能跨域访问服务器的API。
- Access-Control-Allow-Origin: http://www.liuxinxiu.com
浏览器支持情况
HTTP协议之multipart/form-data请求分析
首先来了解什么是multipart/form-data请求:
根据http/1.1 rfc 2616的协议规定,我们的请求方式只有OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE等,那为为何我们还会有multipart/form-data请求之说呢?这就要从头来说了。
http协议大家都知道是规定了以ASCII码传输,建立在tcp、ip协议之上的应用层规范,规范内容把http请求分为3个部门:状态行,请求头,请求体。所有的方法、实现都是围绕如何运用和组织这三部分来完成的。换句话来说就是万变不离其中,只要我们了解了http请求的组成部分后,自然就可以应变任何实际工作中的需求和问题了。
关于状态行,请求头,请求体等三部分的具体内容,大家可以参考官方的协议文档http://www.faqs.org/rfcs/rfc2616.html,这里主要分析multipart/form-data请求具体是怎么一回事。
既然http协议本身的原始方法不支持multipart/form-data请求,那这个请求自然就是由这些原始的方法演变而来的,具体如何演变且看下文:
1、multipart/form-data的基础方法是post,也就是说是由post方法来组合实现的
2、multipart/form-data与post方法的不同之处:请求头,请求体。
3、multipart/form-data的请求头必须包含一个特殊的头信息:Content-Type,且其值也必须规定为multipart/form-data,同时还需要规定一个内容分割符用于分割请求体中的多个post的内容,如文件内容和文本内容自然需要分割开来,不然接收方就无法正常解析和还原这个文件了。具体的头信息如下:
- Content-Type: multipart/form-data; boundary=${bound}
//其中${bound} 是一个占位符,代表我们规定的分割符,可以自己任意规定,但为了避免和正常文本重复了,尽量要使用复杂一点的内容。如:--------------------56423498738365
4、multipart/form-data的请求体也是一个字符串,不过和post的请求体不同的是它的构造方式,post是简单的name=value值连接,而multipart/form-data则是添加了分隔符等内容的构造体。具体格式如下:
- --${bound}
- Content-Disposition: form-data; name="Filename"
- HTTP.pdf
- --${bound}
- Content-Disposition: form-data; name="file000"; filename="HTTP协议详解.pdf"
- Content-Type: application/octet-stream
- %PDF-1.5
- file content
- %%EOF
- --${bound}
- Content-Disposition: form-data; name="Upload"
- Submit Query
- --${bound}--
其中${bound}为之前头信息中的分割符,如果头信息中规定为123,那么这里也要为123,;可以很容易看出,这个请求体是多个相同的部分组成的:每一个部分都是以--加分隔符开始的,然后是该部分内容的描述信息,然后一个回车,然后是描述信息的具体内容;如果传送的内容是一个文件的话,那么还会包含文件名信息,以及文件内容的类型。上面的第二个小部分其实是一个文件体的结构,最后会以--分割符--结尾,表示请求体结束。
综上,可以知道要发送一个multipart/form-data的请求,其实任何支持post请求的工具或语言都可以支持,只是自己要稍微包装一下便可。
mysql 常用SQL汇总
- 1.用管理员登陆
- mysql -u root -p;
- 2.创建数据库
- create database nodeDB;
- 3.删除数据库
- drop database nodeDB;
- 4.查看数据库
- show databases;
- 5.选择目标库
- use nodeDB;
- 6.查看目标表所有字段
- select * from user;
- 7.创建用户
- //user01只能本地访问
- CREATE USER user01@'localhost' IDENTIFIED BY 'user01';
- //user02可以远程访问
- CREATE USER user02@'%' IDENTIFIED BY 'password1';
- 8.修改user01密码
- SET PASSWORD FOR 'user01'@'localhost'=PASSWORD('password2');
- 9.授权
- //user01管理db01全部权限
- GRANT ALL PRIVILEGES ON nodeDB.* TO user01;
- //user02查看权限,并修改密码
- GRANT SELECT ON *.* TO 'user02'@'%' IDENTIFIED by 'password2';
- 10. 刷新数据库
- flush privileges;
创建测试表:
- //判断有库就删除
- drop database if exists school;
- create database school;
- use school;
- create table teacher(
- id int(3) auto_increment not null primary key,
- name char(10) not null,
- address varchar(50) default '深圳',
- year date
- );
- //以下为插入字段
- insert into teacher values(null,'allen','大连一中','1976-10-10');
- insert into teacher values(null,'jack','黄冈中学','1975-12-23');
- insert into teacher values(null,'jesse','北京四中','1980-6-23');
- insert into teacher values(null,'tony','衡水中学','1982-2-12');
NodeJs JSONP数据接口定义
- var http = require('http');
- var urllib = require('url');
- var port = 10011;
- var data = {'name': 'jifeng', 'company': 'taobao'};
- http.createServer(function(req, res){
- var params = urllib.parse(req.url, true);
- console.log(params);
- if (params.query && params.query.callback) {
- //console.log(params.query.callback);
- var str = params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp
- res.end(str);
- } else {
- res.end(JSON.stringify(data));//普通的json
- }
- }).listen(port, function(){
- console.log('server is listening on port ' + port);
- })
自建Node路由Jsonp接口访问地址:http://liuxinxiu.com:3000/jsonp?Jsoncallback=2016&&name=liuxinxiu
- function jsonp(){
- this.exec=function(route,req,res){
- var data1={key:'value',hello:'world',name:'刘新修'};
- var data2={'name':'wangjiang','company':'taobao'};
- console.log(req+'---'+route)
- res.statusCode=200;
- //res.setHeader('content-type','application/json;charset=utf-8');
- //res.setHeader('Content-Type','text/html');
- //req.write(data);
- //req.end();
- var params=url.parse(req.url,true);
- console.log(params);
- if(params.query&¶ms.query.Jsoncallback){
- console.log(params.query.Jsoncallback);
- var str=params.query.Jsoncallback+'('+JSON.stringify(data1)+')';//jsonp
- res.end(str);
- }
- else{
- res.writeHead(200,{'Content-Type':'application/json'});
- res.end(JSON.stringify(data1)); //普通的json
- }
- }
- }
- module.exports=new jsonp();
自建Node路由Jsonp接口访问地址:http://liuxinxiu.com:3000/Jsoncallback?Jsoncallback=1&name=Jack
- function jsoncallback(){
- this.exec=function(route,req,res){
- /******** 处理请求判断用作JSONP ********/
- var params=url.parse(req.url,true);
- /********** 造数据要Obj不要String **********/
- var str2={dataList:[{name:"Jack",age:28,sex:1},{name:'Tony',age:30,sex:0}]};
- /********** 映射数据源无为undefined **********/
- var output=2016+'('+JSON.stringify(str2)+')';
- var result=params.query.Jsoncallback+'('+JSON.stringify(str2)+')';
- /************* 定义头部信息及编码规范 *******************/
- res.writeHead(200,{'content-Type':'application/json;charset=utf-8'});
- /************* 判断出来相应返回的结果 ********************/
- if(params.query&¶ms.query.Jsoncallback){
- res.write(result);
- res.end();
- }
- else{
- res.write(output);
- res.end();
- }
- }
- };
- module.exports=new jsoncallback();
渲染html到页面中,在koa中可以这么干:
- app.get('/',function*(){
- this.body = "<p>'+title+'</p>";
- })
但问题很大,模板混入到js逻辑了,非常不利于维护,基于 mvc 模式,我们需要将html模板抽离到 view 中方便维护,这时候我们就需要一款模板渲染引擎。
为什么选择xtemplate
适用于 koa 的模板引擎选择非常多,比如 jade、ejs、nunjucks、xtemplate 等。
为什么选择 xtemplate 呢?
上手难度
jade 无疑是最独特,上手难度最高,特别是将 html 转成 jade 风格的代码,需要一些成本和适应,特别是空格敏感,经常引起模块渲染报错:
- body
- h1 Jade - node template engine
- #container.col
- if youAreUsingJade
- p You are amazing
- else
- p Get on it!
但 jade 在 express 中拥有广泛的群众基础,所以从 express 转到 koa,jade 是个不错的选择,但我一直认为 jade 不是最佳的模板选择。
ejs、nunjucks、xtemplate 的上手难度差不多,但ejs的扩展写法有些诡异,特别是 filter 的写法:
- <p><%=: users | first | capitalize %></p>
xtemplate 相对于 nunjucks 的优势是,模板的逻辑写法体验更接近js(ejs的逻辑表达也很接近js),上手更为简单,来看下同样一个 if 判断的写法差异。
xtemplate:
- {{#if(variable===0)}}
- It is true
- {{/if}}
nunjucks:
- {% if variable == 0 %}
- It is true
- {% endif %}
所以上手难度:xtemplate < nunjucks < ejs < jade 。
功能的强大度
四款模板引擎必备几样功能都具备:变量、逻辑表达式、循环、layout、include、宏、扩展等。
nunjucks 无疑是功能最全面的模板引擎,xtemplate 拥有 nunjucks 大部分的特性,除了filter,但 xtemplate 拥有非常强悍的拓展性:
- xtpl.addCommand('money',function(scope, option){
- var money = option.params[0];
- if(typeof money !== 'number') return '';
- //金额除以100(接口返回的金额都是以分为单位,转成元)
- var s = Number(money)/100;
- return s;
- })
模板中使用:
- {{money(10000)}}
nunjucks 与 xtemplate 都拥有实用的宏定义功能:
- {{#macro("test","param", default=1)}}
- param is {{param}} {{default}}
- {{/macro}}
模板中使用:
- {{macro("test","2")}}
输出内容:
- param is 2 1
jade 中的 Mixins,ejs 中的 function 也可以实现类似的抽取公用html代码块的目的 。
如果真要分个高下:nunjucks > xtemplate > jade > ejs 。
是否支持前后端混用
jade 直接淘汰,相信在前端js领域一般不会选择 jade 来渲染。
nunjucks 也使用的比较少(ejs其实也少),更多人会选择使用 handlebars 。
xtemplate 目前在阿里的系统中前后端混用中已经得到论证,节约了模板前后端转换的时间。
事实上是否支持前后端混用不是决定性因素,特别是在 angularjs 盛行的年代。
性能考量
它们都很快,其实性能都不是问题,真要较真的话,xtemplate 会更优秀些,可以看 xtemplate benchmark。
个人觉得性能不是决定性因素。
基于上述几点考虑,推荐使用 xtemplate 。