精华内容
下载资源
问答
  • 请问xmpp服务器端怎么做呢 我刚接触,一点头绪都没有
  • 最近需要推送功能,就是一个人申请了...后台采用的是 thinkcmf 开源框架 第三方插件官网也有说怎么做:http://www.thinkcmf.com/document/article/id/395.html   那么先说服务端的: simplewind/Core/Library/Ve

    最近需要推送功能,就是一个人申请了,消息要立马传递给发布的人,就这么一个需求,而且是点对点的推送   就想到了用极光算了


    后台采用的是  thinkcmf 开源框架  第三方插件官网也有说怎么做:http://www.thinkcmf.com/document/article/id/395.html  


    那么先说服务端的:

    simplewind/Core/Library/Vendor   在thinkcmf里面找到这样的地方,然后把第三方的包放在这个下面就可以了

    这里并不采用像 官网上说的那种做法,而是这样的,

    <?php
    class pusher{
        //发送的应用程序
        private $app_key = '你在极光上申请的key';
        //密码
        private $master_secret = '你在极光上申请的那个密码';
        //推送地址
        private $url = 'https://api.jpush.cn/v3/push';
        
        public function __construct($app_key,$master_secret,$url){
            if($app_key) $this->app_key = $app_key;
            if($master_secret) $this->master_secret = $master_secret;
            if($url) $this->url = $url;
        }
        
        /*
         * 需要参数
         * $receive = 'all'  //全部
         * $receive = array('tag'=>array());
         * $receive = array('alias'=>array());  //别名
         * $content = '';   //测试数据
         * $m_type = 'http';    //推送附加字段的类型
         * $m_txt = '';     //推送附加字段类型对应的文字
         * $m_time = '86400';//离线保留时间
         */
        public function send_pub($receive,$content,$m_type,$m_txt,$m_time){
            $m_type = 'http';
            $m_txt = '';
            $m_time = '';
            $message = '';
            $result = $this->push($receive,$content,$m_type,$m_txt,$m_time);
            if($result){
                $res_arr = json_decode($result,true);
                //echo $res_arr['error']['message'];
                $message = '';  //存储推送状态
                if(isset($res_arr['error'])){
                    $error_code = $res_arr['error']['code'];
                    switch($error_code){
                        case 200:
                            $message = '发送成功';
                            break;
                        case 1000:
                            $message = '失败';
                            break;
                        case 1001:
                            $message = '不支持GET方法';
                            break;
                        case 1002:
                            $message = '缺少了必须参数';
                            break;
                        case 1003:
                            $message = '参数不合法';
                            break;
                        case 1004:
                            $message = '验证失败';
                            break;
                        case 1005:
                            $message = '消息体太大';
                            break;
                        case 1008:
                            $message = 'appkey参数非法';
                            break;
                        case 1020:
                            $message = '只支持https';
                            break;
                        case 1030:
                            $message = '内部服务器超时';
                            break;
                        default:
                            $message = '失败 (其他状态)';
                            break;
                    } 
                }else{
                    $message = '发送成功';
                }
            }else{
                $message = '接口调用失败或者无响应';
            }
            echo "<script>alert('推送消息:{$message}')</script>";
        }
        
        
        //
        public function push($receiver = 'all',$content = '' , $m_type , $m_txt , $m_time){
            $base64 = base64_encode("{$this->app_key}:{$this->master_secret}");
            $header = array(
                "Authorization:Basic $base64","Content-Type:application/json"
            );
            $data['platform'] = 'all';
            $data['audience'] = $receiver;
            $data['notification'] = array(
                "alert"=>$content,
                "android"=>array(
                    'alert'=>$content,
                    'title'=>'',
                    'builder_id'=>1,
                    'extras'=>array('type'=>$m_type,'txt'=>$m_txt)
                ),
                "ios"=>array(
                    'alert'=>$content,
                    'badge'=>1,
                    'sound'=>'default',
                    'extras'=>array('type'=>$m_type,'txt'=>$m_txt)
                )
            );
            $data['message'] = array(
                'msg_content'=>$content,
                'extras'=>array('type'=>$m_type,'txt'=>$m_txt)
            );
            $data['option'] = array(
                'sendno'=>time(),
                'time_to_live'=>$m_time,
                'apns_production'=>fals,    //当前是开发环境还是生产环境
            );
            $param = json_encode($data);
            $res = $this->push_curl($param,$header);
            if($res){
                return $res;
            }else{
                return false;
            }
        }
        
        //通过curl进行推送
        public function push_curl($param = '',$header = ''){
            if(empty($param)) return false;
            $postUrl = $this->url;
            $curlPost = $param;
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL ,$postUrl);
            curl_setopt($ch, CURLOPT_HEADER , 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POST , 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $curlPost );
            curl_setopt($ch, CURLOPT_HTTPHEADER , $header);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            $data = curl_exec($ch);
            curl_close($ch);
            return $data;
        }  
    }

    把这个文件放在Vendor 下面就可以 其他的不用管,

    接下来就是在application下面建一个模块  暂时定为 JPush

    写一个控制器

    <?php
    namespace JPusher\Controller;
    use Common\Controller\HomeBaseController;
    class JPusherController extends HomeBaseController{
       public function push(){
                vendor('pusher');
                $pusher = new \pusher();
                $a = array(
                    'id'=>12,
                    'msg'=>'hello world',
                    'name'=>'呵呵'
                );
                $pusher->send_pub('all', json_encode($a), 'http', 'http://www.baidu.com', '12000');
    
       }
    
    }

    测试的时候采用的是广播形式推送  你可以把那个all改成  tag传送  ;改成alais别名推送 等

    服务器端就写好了,接下来就是android端:

    客户端首先是清单文件要把  在极光上申请的demo 全部copy一份到你现在的工程里面,主要包名要一致的哦,

    然后是在自定义的application全局变量onCreate()里面加上这样两句:

             //极光推送
             JPushInterface.setDebugMode(true);
             JPushInterface.init(this);


    接下来是建个包或者在工具包里面写个接收的工具类:

    import org.json.JSONException;
    import org.json.JSONObject;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import cn.jpush.android.api.JPushInterface;
    
    /**
     * 自定义接收器
     * 
     * 如果不定义这个 Receiver,则:
     * 1) 默认用户会打开主界面
     * 2) 接收不到自定义消息
     */
    public class MyReceiver extends BroadcastReceiver {
    	private static final String TAG = "JPush";
    
    	@Override
    	public void onReceive(Context context, Intent intent) {
            Bundle bundle = intent.getExtras();
    		Log.d(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle));
    		
            if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {
                String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);
                Log.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);
                //send the Registration Id to your server...
                            
            } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
            	Log.d(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));
            	processCustomMessage(context, bundle);
            
            } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {
                Log.d(TAG, "[MyReceiver] 接收到推送下来的通知");
                int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);
                Log.d(TAG, "[MyReceiver] 接收到推送下来的通知的ID: " + notifactionId);
            	
            } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
                Log.d(TAG, "[MyReceiver] 用户点击打开了通知");
                
            	//打开自定义的Activity
            	Intent i = new Intent(context, TestActivity.class);
            	i.putExtras(bundle);
            	//i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            	i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );
            	context.startActivity(i);
            	
            } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {
                Log.d(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));
                //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等..
            	
            } else if(JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {
            	boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);
            	Log.w(TAG, "[MyReceiver]" + intent.getAction() +" connected state change to "+connected);
            } else {
            	Log.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction());
            }
    	}
    
    	// 打印所有的 intent extra 数据
    	private static String printBundle(Bundle bundle) {
    		StringBuilder sb = new StringBuilder();
    		for (String key : bundle.keySet()) {
    			if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
    				sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));
    			}else if(key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)){
    				sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));
    			} 
    			else {
    				sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
    			}
    		}
    		return sb.toString();
    	}
    	
    	//send msg to MainActivity
    	private void processCustomMessage(Context context, Bundle bundle) {
    		if (MainActivity.isForeground) {
    			String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
    			String extras = bundle.getString(JPushInterface.EXTRA_EXTRA);
    			Intent msgIntent = new Intent(MainActivity.MESSAGE_RECEIVED_ACTION);
    			msgIntent.putExtra(MainActivity.KEY_MESSAGE, message);
    			if (!ExampleUtil.isEmpty(extras)) {
    				try {
    					JSONObject extraJson = new JSONObject(extras);
    					if (null != extraJson && extraJson.length() > 0) {
    						msgIntent.putExtra(MainActivity.KEY_EXTRAS, extras);
    					}
    				} catch (JSONException e) {
    
    				}
    
    			}
    			context.sendBroadcast(msgIntent);
    		}
    	}
    }
    

    这里面是你自己想要啥就保留啥,这是官网给的demo 

    接下来就是点对点推送需要在用户登录的时候或者注册的时候你把用户的昵称  (别名)到极光那边注册下

    	//初始化jpush
    	private void initJpush()
    	{
    		new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				// TODO Auto-generated method stub
    				JPushInterface.setAliasAndTags(getApplicationContext(), uid, null, mTagAliasCallback);
    			}
    		}).start();
    	}
    	
    	//下面是极光注册别名的时候的回调函数
    	private final TagAliasCallback mTagAliasCallback = new TagAliasCallback() {
    		
    		@Override
    		public void gotResult(int arg0, String arg1, Set<String> arg2) 
    		{
    			// TODO Auto-generated method stub
    			switch(arg0)
    			{
    			case 0:
    				cacheFunction.upDateCache(Constants.INIT_JPUSH, "1");
    				handler.sendEmptyMessage(INIT_JPUSH);
    				break;
    			default:
    				handler.sendEmptyMessage(INIT_JPUSH_FAILURE);
    				break;
    			}
    		}
    	};

    这个代码是放在注册或者登录里面的,当你注册成功之后服务器返回状态码,判断之后就调用initJpush就可以了,

    其他的还有几个小地方就不说了 大致上就这样


    展开全文
  • 需要从客户端发送消息到服务端,服务端能解析消息并作出返回响应。
  • android怎么做一个pc服务器和手机的app 我做的android,写好后,只能在手机执行,在bin文件夹中有apk文件。我如果要在电脑里执行,是需要是.exe尾缀的文件,才能在电脑执行,我该怎么做呢?本人菜鸟,求...

    android怎么做一个pc端的服务器和手机端的app

    我做的android,写好后,只能在手机端执行,在bin文件夹中有apk文件。我如果要在电脑里执行,是需要是.exe尾缀的文件,才能在电脑端执行,我该怎么做呢?
    还是android只能做手机端的app,exe要用java其他做。
    本人菜鸟,求大神指教!

    展开全文
  • 我考虑是不是频繁调用数据库造成的,所以考虑在服务器端直接缓存生成的试题数据,然后前台直接调用就行;还有一个方法就是在前台直接调用所有试题,然后缓存在客户端,用户直接调用本地缓存就行! 有没有人过?...
  • 现在服务器端的发现功能和视频等其他功能完了。用odm,odt都能正常使用。但是没有用户验证机制,想问一下大家如何加入密码验证机制,我现在用odm,如果随便输入用户密码的话就不能使用![图片说明]...
  • delphi7的WEBService服务器端怎么访问和操作sql数据库呢 能访问吗,用ADO等控件吗,有什么讲究? 初步测试了一下,好像不行
  • AJAX发起的请求,服务器端(Filter)如果不通过,如session失效了需要重定向到登陆页面,该怎么做
  • 手机端怎么播放视频swf 服务器是iis7.0.需要什么操作
  • 请问: 实现与服务器端的数据库建立联接,然后对其操作. 获取到的数据存入服务器端的数据库... 读取服务器端的数据库的数据到本地PC机使用... 可以的话,贴几句代码。谢谢!
  • 苹果内购 JAVA服务端接口应该怎么写,公司了一个APP卖的是虚拟产品,第三方支付走不同,要走苹果内购,可是没有接触过苹果内购这个东西,一直都是JAVA的 简单看了一些文档,需要挺多的 ...服务器端是JAVA的
  • Web components(网页组件)用在服务器端渲染早已被大家所了解,在本文中,我想谈及的是:你还可以用 web components 构建服务器端应用。 先来回顾一下,web components 是一组新提出的标准,提供了模块化打包 UI ...
    本文讲的是为什么我们要用网页端组件去构建服务器?该怎么做?,

    Web components(网页组件)用在服务器端渲染早已被大家所了解,在本文中,我想谈及的是:你还可以用 web components 构建服务器端应用。

    先来回顾一下,web components 是一组 新提出的标准,提供了模块化打包 UI 组件的能力,这些组件具有可重用、声明式的特点,因此具有方便分享、容易组合到应用的优势。现在 web components 已经开始应用到前端开发当中了,但服务器端呢?Polymer 项目 给了我们启发,web components 不仅对于 UI 组件很有用,而且还可以用在原始功能中。接下来我们会看看 web components 如何应用到服务器端,并分析其优势。

    • 声明式
    • 模块化
    • 通用化
    • 可共享
    • 可调试
    • 更平缓的学习曲线
    • 客户端结构

    声明式

    首先,web components 让你得到了声明式的服务器。以下是一个使用 Express Web Components 编写 Express.js 应用程序的简单示例:

    <link rel="import" href="bower_components/polymer/polymer.html">
    <link rel="import" href="bower_components/express-web-components/express-app.html">
    <link rel="import" href="bower_components/express-web-components/express-middleware.html">
    <link rel="import" href="bower_components/express-web-components/express-router.html">
    
    <dom-module id="example-app">
        <template>
            <express-app port="5000">
                <express-middleware method="get" path="/" callback="[[indexHandler]]"></express-middleware>
                <express-middleware callback="[[notFound]]"></express-middleware>
            </express-app>
        </template>
    
        <script>
            class ExampleAppComponent {
                beforeRegister() {
                    this.is = 'example-app';
                }
    
                ready() {
                    this.indexHandler = (req, res) => {
                        res.send('Hello World!');
                    };
    
                    this.notFound = (req, res) => {
                        res.status(404);
                        res.send('not found');
                    };
                }
            }
    
            Polymer(ExampleAppComponent);
        </script>
    </dom-module>
    

    现在你可以使用 HTML 语法来声明路由了。比起纯 JavaScript 语法,现在的路由可以体现出视觉层次感,看起来更加形象和易于理解。拿上面的例子来说,所有和 Express 框架有关的 endpoints(路由) / middleware(中间件) 都嵌套在 <express-app> 元素,连接 app 的中间件按顺序放在 <express-middleware> 元素中。而路由也可以很容易地嵌套,<express-router> 中包含的每个中间件都会连接到 router,你还可以把 <express-route> 放在 <express-router> 元素中。

    模块化

    使用 Express 和 Node.js 已经让我们实现了模块化,但我觉得模块化 web components 更加简单。以下 这个例子 把模块化的自定义元素和 Express Web Components 结合起来使用:

    <!--index.html-->
    
    <!DOCTYPE html>
    
    <html>
        <head>
            <script src="../../node_modules/scram-engine/filesystem-config.js"></script>
            <link rel="import" href="components/app/app.component.html">
        </head>
    
        <body>
            <na-app></na-app>
        </body>
    
    </html>
    

    index.html 是入口文件,实际上我们需要关心的地方只有一个,就是 <na-app></na-app> :

    <!--components/app/app.component.html-->
    
    <link rel="import" href="../../../../bower_components/polymer/polymer.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-app.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-middleware.html">
    <link rel="import" href="../api/api.component.html">
    
    <dom-module id="na-app">
        <template>
            <express-app port="[[port]]" callback="[[appListen]]">
                <express-middleware callback="[[morganMW]]"></express-middleware>
                <express-middleware callback="[[bodyParserURLMW]]"></express-middleware>
                <express-middleware callback="[[bodyParserJSONMW]]"></express-middleware>
                <na-api></na-api>
            </express-app>
        </template>
    
        <script>
            class AppComponent {
                beforeRegister() {
                    this.is = 'na-app';
                }
    
                ready() {
                    const bodyParser = require('body-parser');
                    const morgan = require('morgan');
    
                    this.morganMW = morgan('dev'); // 把请求记录在控制台
    
                    // 配置 body parser
                    this.bodyParserURLMW = bodyParser.urlencoded({ extended: true });
                    this.bodyParserJSONMW = bodyParser.json();
    
                    this.port = process.env.PORT || 8080; // 设置端口
    
                    const mongoose = require('mongoose');
                    mongoose.connect('mongodb://@localhost:27017/test'); // 连接数据库
    
                    this.appListen = () => {
                        console.log(`Magic happens on port ${this.port}`);
                    };
                }
            }
    
            Polymer(AppComponent);
        </script>
    </dom-module>
    

    我们启动 Express 应用,监听 port 8080 或者 process.env.PORT 端口,然后定义了三个中间件和一个自定义元素。希望你直觉上就能理解那三个中间件会在<na-api></na-api> 之前运行的工作原理:

    <!--components/api/api.component.html-->
    
    <link rel="import" href="../../../../bower_components/polymer/polymer.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-middleware.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-router.html">
    <link rel="import" href="../bears/bears.component.html">
    <link rel="import" href="../bears-id/bears-id.component.html">
    
    <dom-module id="na-api">
        <template>
            <express-router path="/api">
                <express-middleware callback="[[allMW]]"></express-middleware>
                <express-middleware method="get" path="/" callback="[[indexHandler]]"></express-middleware>
                <na-bears></na-bears>
                <na-bears-id></na-bears-id>
            </express-router>
        </template>
    
        <script>
            class APIComponent {
                beforeRegister() {
                    this.is = 'na-api';
                }
    
                ready() {
                    // 这个中间件应用在 /api 前缀开头的所有请求
                    this.allMW = (req, res, next) => {
                        // 输出日志
                        console.log('Something is happening.');
                        next();
                    };
    
                    // 测试路由,目的是确保功能正常 (通过 GET http://localhost:8080/api 访问)
                    this.indexHandler = (req, res) => {
                        res.json({ message: 'hooray! welcome to our api!' });
                    };
                }
            }
    
            Polymer(APIComponent);
        </script>
    </dom-module>
    

    所有 <na-api></na-api> 的内容都包裹在 <express-router></express-router> 当中。组件里的所有中间件都在访问 /api 时生效。接下来再看看 <na-bears></na-bears> 和 <na-bears-id></na-bears-id>

    <!--components/bears/bears.component.html-->
    
    <link rel="import" href="../../../../bower_components/polymer/polymer.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-middleware.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-route.html">
    
    <dom-module id="na-bears">
        <template>
            <express-route path="/bears">
                <express-middleware method="post" callback="[[createHandler]]"></express-middleware>
                <express-middleware method="get" callback="[[getAllHandler]]"></express-middleware>
            </express-route>
        </template>
    
        <script>
            class BearsComponent {
                beforeRegister() {
                    this.is = 'na-bears';
                }
    
                ready() {
                    var Bear = require('./models/bear');
    
                    // 创建一只熊 (调用 POST http://localhost:8080/bears)
                    this.createHandler = (req, res) => {
                        var bear = new Bear();      // create a new instance of the Bear model
                        bear.name = req.body.name;  // set the bears name (comes from the request)
    
                        bear.save(function(err) {
                            if (err)
                                res.send(err);
                            res.json({ message: 'Bear created!' });
                        });
                    };
    
                    // 获取所有熊 (调用 GET http://localhost:8080/api/bears)
                    this.getAllHandler = (req, res) => {
                        Bear.find(function(err, bears) {
                            if (err)
                                res.send(err);
                            res.json(bears);
                        });
                    };
                }
            }
    
            Polymer(BearsComponent);
        </script>
    </dom-module>
    
    <!--components/bears-id/bears-id.component.html-->
    
    <link rel="import" href="../../../../bower_components/polymer/polymer.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-middleware.html">
    <link rel="import" href="../../../../bower_components/express-web-components/express-route.html">
    
    <dom-module id="na-bears-id">
        <template>
            <express-route path="/bears/:bear_id">
                <express-middleware method="get" callback="[[getHandler]]"></express-middleware>
                <express-middleware method="put" callback="[[updateHandler]]"></express-middleware>
                <express-middleware method="delete" callback="[[deleteHandler]]"></express-middleware>
            </express-route>
        </template>
    
        <script>
            class BearsIdComponent {
                beforeRegister() {
                    this.is = 'na-bears-id';
                }
    
                ready() {
                    var Bear = require('./models/bear');
    
                    // 根据 id 获取某只熊
                    this.getHandler = (req, res) => {
                        console.log(req.params);
                        Bear.findById(req.params.bear_id, function(err, bear) {
                            if (err)
                                res.send(err);
                            res.json(bear);
                        });
                    };
    
                    // 根据 id 修改某只熊
                    this.updateHandler = (req, res) => {
                        Bear.findById(req.params.bear_id, function(err, bear) {
                            if (err)
                                res.send(err);
                            bear.name = req.body.name;
                            bear.save(function(err) {
                                if (err)
                                    res.send(err);
                                res.json({ message: 'Bear updated!' });
                            });
                        });
                    };
    
                    // 根据 id 删除某只熊
                    this.deleteHandler = (req, res) => {
                        Bear.remove({
                            _id: req.params.bear_id
                        }, function(err, bear) {
                            if (err)
                                res.send(err);
                            res.json({ message: 'Successfully deleted' });
                        });
                    };
                }
            }
    
            Polymer(BearsIdComponent);
        </script>
    </dom-module>
    

    如你所见,所有路由都被分离到各自的组件中,并且要包含在 app 中也很容易。在 index.html 文件中的 import 引入方法非常浅显易懂,

    通用性

    我喜欢 JavaScript 的原因之一,就是可以在客户端和服务器端共享代码。虽然现在某种程度上可以说这是可行的,但实际上,由于某些 API 的缺失,依然有一部分客户端的库不能在服务器端工作,反之亦然。从根本上说,Node.js 和浏览器依然是提供不同 API 的两套环境。那有什么办法可以结合呢?我们想到了 Electron,Electron 把 Node.js 和 Chromium 项目结合成为一个单独的运行环境,使得客户端代码和服务端代码结合运行成为了可能。

    Scram.js 这个小项目可以帮你轻松运行 Electron,使得运行服务端 web components 和其它 Node.js 应用一样容易。

    我已经做出了一些小应用,并放上了生产环境。如果你感兴趣,可以看看 Dokku Example 。

    现在,我来告诉你在开发服务端 Web components 过程中一件有意思的事情。我使用一个 客户端的 JavaScript 库 进行某些特定的 API 请求。然而,假如请求放在客户端,就必须把我们数据库的凭证泄露给客户端。为了保证凭证安全,我们需要把请求放在服务端进行。假如要在 Node.js 运行这个库,需要对代码进行大幅重构,幸亏我们用上了 Electron 和 Scram.js,我只需要导入这个库,无需任何代码改动,就顺利在服务端运行起来了!

    我只需要导入这个库,无需任何代码改动,就顺利在服务端运行起来了!

    另外,我曾经使用 JavaScript 构建一些移动端应用。我们使用 localForage 作为客户端数据库。这个应用是基于分布式数据库设计的,可以在没有中心服务器的情况下进行互相通信。我希望可以在 Node.js 环境下使用 localForage,使得模型可以重用,以及不需要太多修改就能把功能跑起来。过去我们不能做到这点,但现在我们可以做到了。

    Electron 和 Scram.js 提供了 LocalStorage, Web SQL 和 IndexedDB,使得 localForage 成为了可能。我们就这样搭建起了一个简单的服务器端数据库!

    虽然我不确定怎样测量其性能,但至少这个方法是可行的。

    而且,现在你可以在服务端使用像 iron-ajax 和我的 redux-store-element 组件了,使用方法和客户端一样。我希望这么做可以让客户端的范式可重用,并减少从客户端到服务端之间因环境切换而产生的不可避免的差异性。

    可共享

    这点完全得益于 web components,因为 web components 的其中一个主要目标就是使得组件易于共享,实现跨浏览器通用,并停止在同一个问题上因为框架或者库的改变而不断重复实现。共享之所以变得可能,是因为 web components 基于现有的或者提出的标准,所有主流浏览器的厂商都会想办法去实现。

    这意味着 web components 不依赖于任何框架或者库,就可以在任何 web 平台上通用。

    我希望有更多人能参与到创建服务器端 web components 的创建当中,并把各种功能打包成组件,就像前端组件那样。我从 Express components 开始了这项工作,但我还期待看到 Koa, Hapi.js, Socket.io, MongoDB 等组件的出现。

    可调试

    Scram.js 有一个 -d 选项,让你可以在调试时打开 Electron 窗口。现在你可以使用 Chrome 开发者工具的所有功能来帮助你调试服务器了。断点、控制台日志、网络信息等都可以在里面看到。Node.js 的服务端调试似乎总是我的第二选择,但现在它的确已经集成到了平台中:

    更平缓的学习曲线

    服务端 web components 对降低后端编程学习难度有帮助。要知道有很多 web 设计师、交互设计和其他一些只懂 HTML 和 CSS 的人希望学习服务端开发,但现有的服务器端代码对于他们而言很难理解。然而,如果使用他们熟悉的 HTML 来编写,特别是用上语义化的自定义元素,他们就能更容易地上手服务器端编程了。至少我们可以降低他们的学习曲线吧。

    客户端架构

    客户端和服务端 app 的架构正变得越来越像了。每个 app 以 index.html 文件开始,然后引入相关组件。这只是一种新的统一前后端的方法。在过去,我觉得想要找到服务器端应用的入口多少有点困难,如果后端能像前端应用一样,以 index.html 作为标准的入口,不是挺好的吗?

    以下是使用 web components 构建的客户端应用的一般结构:

    app/
    ----components/
    --------app/
    ------------app.component.html
    ------------app.component.js
    --------blog-post/
    ------------blog-post.component.html
    ------------blog-post.component.js
    ----models/
    ----services/
    ----index.html
    

    以下是使用 web components 构建的服务端应用的一般结构:

    app/
    ----components/
    --------app/
    ------------app.component.html
    ------------app.component.js
    --------api/
    ------------api.component.html
    ------------api.component.js
    ----models/
    ----services/
    ----index.html
    

    这两种结构应该都可以很好地工作,现在我们成功减少了从客户端到服务端切换的上下文数量,反之亦然。

    可能存在的问题

    Electron 在服务器生产环境中的性能和稳定性,是最有可能导致应用崩溃的原因。话虽这么说,我并不觉得性能在将来是一个大问题,因为 Electron 只是通过一个渲染进程运行 Node.js 代码,我猜想和原生 Node.js 的运行状况差不多。最大问题是,Chromium 的运行时能否足够稳定,坚持运行足够长时间(而不发生内存泄露)。

    另一个潜在问题是冗余性,相比原生 JavaScript 逻辑,使用服务端 web components 完成相同任务会花费更多时间,因为标记语言需要解析。话虽这么说,我依然希望付出冗余的代价,能换来更容易理解的代码。

    性能测试

    基于好奇心,我进行了一系列基础测试,对比同一个 应用 在原生 Node.js + Express 框架,和 Electron + Scram.js 的 Express Web Components 运行性能对比。下面的图标展示出对于主路由使用node-ab 库进行压力测试的结果。以下是测试用到的一些参数:

    • 在本地机器上运行
    • 每秒递增 100 次 GET 请求
    • 运行直到有 1% 的请求返回不成功
    • 对于 Node.js app 和 Electron/Scram.js app 版本,分别运行 10 次测试
    • Node.js app
      • 使用 Node.js v6.0.0 版本
      • 使用 Express v4.10.1 版本
    • Electron/Scram.js app
      • 使用 Scram.js v0.2.2 版本
        • 默认设置(从本地服务器加载起始 html 文件)
        • 调试窗口关闭
      • 使用 Express v4.10.1 版本
      • 使用 electron-prebuilt v1.2.1 版本
    • 运行库: https://github.com/doubaokun/node-ab
    • 运行命令: nab http://localhost:3000 --increase 100 --verbose

    以下是结果 (QPS: Queries Per Second 每秒查询数):

    出乎意料,Electron/Scram.js 比 Node.js 性能更佳。我们对这个结果持保留意见,但起码还是能反映出使用 Electron 作为服务器的性能不会比 Node.js 差很远,至少在短期内处理原始请求的效果是如此。还记得我之前说过“我并不觉得性能在将来是一个大问题”吗?结果证实了我的描述。

    总结

    Web components 很好很强大,给 Web 平台带来了标准化、声明式的组件模型。Web components 不仅能给客户端带来便利,而且在服务端也获益良多。客户端和服务端之间的差距正在缩小,我相信服务器端 web components 是正确方向上的一大迈进。因此,一起来使用它们构建我们的应用吧!






    原文发布时间为:2016年08月02日

    本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
    展开全文
  • 服务器端程序有时候会死锁或崩溃,bug太多,段时间内无法解决。 想用个看门狗程序实现服务器端程序的自动重启。 有经验的达人,能不能说一下思路?
  • 小白问: 网页上别人点一下链接,服务器端就跳出消息提示,怎么做比较方便? 可以用js么?
  • 想用pyqt5桌面程序,但是后端还想使用django,不知道有人有这种交互的案例吗?</p>
  • 我们用C++在本地写的客户端,然后想用PHP在服务器端写个程序把这个文件接受存储,是不是在服务器要写个监听程序,还是要怎么来把他们链接起来实现数据传输回复讨论(解决方案)用 post 方式加 multipart/form-data 头...

    我们用C++在本地写的客户端,然后想用PHP在服务器端写个程序把这个文件接受存储,是不是在服务器要写个监听程序,还是要怎么来把他们链接起来实现数据传输

    回复讨论(解决方案)

    用 post 方式加 multipart/form-data 头

    php 会自动识别上传的文件

    如果用 put 方式,则需在 平衡品端从 php://input 资源读取文件内容

    用 post 方式加 multipart/form-data 头

    php 会自动识别上传的文件

    如果用 put 方式,则需在 平衡品端从 php://input 资源读取文件内容 能不能写几行具体的代码,PHP我也是刚开始学新手,谢谢了

    if(isset($_FILES['上传时指定的变量名']['tmp_name')) { move_uploaded_file($_FILES['上传时指定的变量名']['tmp_name'], '目标文件名');}else { $s = file_get_contents('php://input'); if($s) { file_put_contents('目标文件名', $s); }}

    用 post 方式加 multipart/form-data 头

    php 会自动识别上传的文件

    如果用 put 方式,则需在 平衡品端从 php://input 资源读取文件内容 我这里有个程序,我不懂人家这个

    这个是标准的文件上传程序,建议去看看php手册就明白了。

    建议看看手册 $_FILES 有说明有例子

    嗯谢谢各位了,我继续去看看PHP手册

    本文原创发布php中文网,转载请注明出处,感谢您的尊重!

    展开全文
  • 一个检测用户实时在线的功能,网上找了一个例子,在本地可以查看到用户在线 情况,但是怎么将服务端部署到服务器呢,实现客户端发送心跳包给服务器
  • 1. 服务器初次创建session的时候后返回session到客服(在返回头中有setCookie) 2. 浏览器会把sessionname->sessionid存到cooike中, 3. 下再次请求服务器时,会自动在请求头中带上cooike信息,服务器可以在_...
  • 如题,急急,各位大侠帮帮忙,今天下班之间不出来就要被炒了
  • table自带的筛选功能是做已有数据的筛选,如果做了分页,就是在当前页做筛选,数据量大的时候显然不合适,下面介绍一下怎么做服务器端筛选 1,首先table本身带有一个事件@filter-change(这个事件是触发筛选的...
  • 如题所说,winform窗口这方面一直很不错,但是C#的mvc用着不是很好,准备一个winform与javaweb交互的项目,请问我该怎么实现?网上和搜了好久一直没有思路。谢谢
  • 1、linux操作系统是redhat7.0 2、服务器ip是192.168.91.136。客户端ip是192.168.91.200 ...我该怎么配置,或者怎么写脚本,才能在查看服务器日志审计记录时,显示的是上传的客户端的ip地址而不是localhost呢?
  • 排队叫号系统。一个android系统控制,一个android系统显示信息。有人说是双向通信。怎么实现?是否可以用来显示的android 同时充当服务器和客户端呢?
  • 一个多人聊天系统,客户端发送数据给服务器服务器再把得到的数据传给其他客户端 现在可以接受客户来的消息,但是要怎么发给其他的客户端?
  • 因为以前的都是C,C++的,刚转投JAVA门下,遇到了很多问题。 今天要说的问题就是,不使用netty的心跳机制,然后如何判断终端的设备掉线了。 先上结论,复写ChannelHandlerAdapter中的handlerRemoved。 @...
  • [color=#000000]rt.[/color]
  • 求教各位大神,用c#怎么写websocket实现服务器端主动发消息给web客户端的功能。就比如数据库的数据更新了,服务器就主动发更新的消息给客户端。求代码啊
  • <div><p>我在ie8下的调试,但是不是很明白你们提供的IE8/9的Note的意思。 项目后端用的nodejs,目前返回的结果是 <pre><code> <script>document.domain="localhost"</script>...
  • 做服务器端OAuth2,引用了客户端的相关jar 会报错: Description: Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration ...
  • 在使用TENSORFLOWGPU计算时,借用的别人搭服务器。这里需要使用SSH方式登录。以下是具体操作。ssh -p 端口 hostNAME@IP选择yesssh -p 1802 canpi@58.49.127.118然后输入source activate py_tfnvidia-smipython ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,206
精华内容 482
关键字:

服务器端怎么做