欢迎各位兄弟 发布技术文章
这里的技术是共享的
WebSocket是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给浏览器。
为什么传统的HTTP协议不能做到WebSocket实现的功能?这是因为HTTP协议是一个请求-响应协议,请求必须先由浏览器发给服务器,服务器才能响应这个请求,再把数据发送给浏览器。换句话说,浏览器不主动请求,服务器是没法主动发数据给浏览器的。
这样一来,要在浏览器中搞一个实时聊天,在线炒股(不鼓励),或者在线多人游戏的话就没法实现了,只能借助Flash这些插件。
也有人说,HTTP协议其实也能实现啊,比如用轮询或者Comet。轮询是指浏览器通过JavaScript启动一个定时器,然后以固定的间隔给服务器发请求,询问服务器有没有新消息。这个机制的缺点一是实时性不够,二是频繁的请求会给服务器带来极大的压力。
Comet本质上也是轮询,但是在没有消息的情况下,服务器先拖一段时间,等到有消息了再回复。这个机制暂时地解决了实时性问题,但是它带来了新的问题:以多线程模式运行的服务器会让大部分线程大部分时间都处于挂起状态,极大地浪费服务器资源。另外,一个HTTP连接在长时间没有数据传输的情况下,链路上的任何一个网关都可能关闭这个连接,而网关是我们不可控的,这就要求Comet连接必须定期发一些ping数据表示连接“正常工作”。
以上两种机制都治标不治本,所以,HTML5推出了WebSocket标准,让浏览器和服务器之间可以建立无限制的全双工通信,任何一方都可以主动发消息给对方。
WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。我们来看看WebSocket连接是如何创建的。
首先,WebSocket连接必须由浏览器发起,因为请求协议是一个标准的HTTP请求,格式如下:
GET ws://localhost:3000/ws/chat HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Origin: http://localhost:3000
Sec-WebSocket-Key: client-random-string
Sec-WebSocket-Version: 13
该请求和普通的HTTP请求有几点不同:
GET请求的地址不是类似/path/
,而是以ws://
开头的地址;
请求头Upgrade: websocket
和Connection: Upgrade
表示这个连接将要被转换为WebSocket连接;
Sec-WebSocket-Key
是用于标识这个连接,并非用于加密数据;
Sec-WebSocket-Version
指定了WebSocket的协议版本。
随后,服务器如果接受该请求,就会返回如下响应:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: server-random-string
该响应代码101
表示本次连接的HTTP协议即将被更改,更改后的协议就是Upgrade: websocket
指定的WebSocket协议。
版本号和子协议规定了双方能理解的数据格式,以及是否支持压缩等等。如果仅使用WebSocket的API,就不需要关心这些。
现在,一个WebSocket连接就建立成功,浏览器和服务器就可以随时主动发送消息给对方。消息有两种,一种是文本,一种是二进制数据。通常,我们可以发送JSON格式的文本,这样,在浏览器处理起来就十分容易。
为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?实际上HTTP协议是建立在TCP协议之上的,TCP协议本身就实现了全双工通信,但是HTTP协议的请求-应答机制限制了全双工通信。WebSocket连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用HTTP协议了,直接互相发数据吧。
安全的WebSocket连接机制和HTTPS类似。首先,浏览器用wss://xxx
创建WebSocket连接时,会先通过HTTPS创建安全的连接,然后,该HTTPS连接升级为WebSocket连接,底层通信走的仍然是安全的SSL/TLS协议。
很显然,要支持WebSocket通信,浏览器得支持这个协议,这样才能发出ws://xxx
的请求。目前,支持WebSocket的主流浏览器如下:
Chrome
Firefox
IE >= 10
Sarafi >= 6
Android >= 4.4
iOS >= 8
由于WebSocket是一个协议,服务器具体怎么实现,取决于所用编程语言和框架本身。Node.js本身支持的协议包括TCP协议和HTTP协议,要支持WebSocket协议,需要对Node.js提供的HTTPServer做额外的开发。已经有若干基于Node.js的稳定可靠的WebSocket实现,我们直接用npm安装使用即可。
来自 https://www.liaoxuefeng.com/wiki/1022910821149312/1103303693824096
要使用WebSocket,关键在于服务器端支持,这样,我们才有可能用支持WebSocket的浏览器使用WebSocket。
在Node.js中,使用最广泛的WebSocket模块是ws
,我们创建一个hello-ws
的VS Code工程,然后在package.json
中添加ws
的依赖:
"dependencies": {
"ws": "1.1.1"
}
整个工程结构如下:
hello-ws/
|
+- .vscode/
| |
| +- launch.json <-- VSCode 配置文件
|
+- app.js <-- 启动js文件
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包
运行npm install
后,我们就可以在app.js
中编写WebSocket的服务器端代码。
创建一个WebSocket的服务器实例非常容易:
// 导入WebSocket模块:
const WebSocket = require('ws');
// 引用Server类:
const WebSocketServer = WebSocket.Server;
// 实例化:
const wss = new WebSocketServer({
port: 3000
});
这样,我们就在3000端口上打开了一个WebSocket Server,该实例由变量wss
引用。
接下来,如果有WebSocket请求接入,wss
对象可以响应connection
事件来处理这个WebSocket:
wss.on('connection', function (ws) {
console.log(`[SERVER] connection()`);
ws.on('message', function (message) {
console.log(`[SERVER] Received: ${message}`);
ws.send(`ECHO: ${message}`, (err) => {
if (err) {
console.log(`[SERVER] error: ${err}`);
}
});
})
});
在connection
事件中,回调函数会传入一个WebSocket
的实例,表示这个WebSocket连接。对于每个WebSocket连接,我们都要对它绑定某些事件方法来处理不同的事件。这里,我们通过响应message
事件,在收到消息后再返回一个ECHO: xxx
的消息给客户端。
现在,这个简单的服务器端WebSocket程序就编写好了。如何真正创建WebSocket并且给服务器发消息呢?方法是在浏览器中写JavaScript代码。
先在VS Code中执行app.js
,或者在命令行用npm start
执行。然后,在当前页面下,直接打开可以执行JavaScript代码的浏览器Console,依次输入代码:
// 打开一个WebSocket:
var ws = new WebSocket('ws://localhost:3000/test');
// 响应onmessage事件:
ws.onmessage = function(msg) { console.log(msg); };
// 给服务器发送一个字符串:
ws.send('Hello!');
一切正常的话,可以看到Console的输出如下:
MessageEvent {isTrusted: true, data: "ECHO: Hello!", origin: "ws://localhost:3000", lastEventId: "", source: null…}
这样,我们就在浏览器中成功地收到了服务器发送的消息!
如果嫌在浏览器中输入JavaScript代码比较麻烦,我们还可以直接用ws
模块提供的WebSocket
来充当客户端。换句话说,ws
模块既包含了服务器端,又包含了客户端。
ws
的WebSocket
就表示客户端,它其实就是WebSocketServer响应connection
事件时回调函数传入的变量ws
的类型。
客户端的写法如下:
let ws = new WebSocket('ws://localhost:3000/test');
// 打开WebSocket连接后立刻发送一条消息:
ws.on('open', function () {
console.log(`[CLIENT] open()`);
ws.send('Hello!');
});
// 响应收到的消息:
ws.on('message', function (message) {
console.log(`[CLIENT] Received: ${message}`);
}
在Node环境下,ws
模块的客户端可以用于测试服务器端代码,否则,每次都必须在浏览器执行JavaScript代码。
从上面的测试可以看出,WebSocket协议本身不要求同源策略(Same-origin Policy),也就是某个地址为http://a.com
的网页可以通过WebSocket连接到ws://b.com
。但是,浏览器会发送Origin
的HTTP头给服务器,服务器可以根据Origin
拒绝这个WebSocket请求。所以,是否要求同源要看服务器端如何检查。
还需要注意到服务器在响应connection
事件时并未检查请求的路径,因此,在客户端打开ws://localhost:3000/any/path
可以写任意的路径。
实际应用中还需要根据不同的路径实现不同的功能。
老师我这边已经和后端握手成功了,控制台能输出后端的数据。但是我想把获取的数据传给其他函数要怎么做。我试了下赋值给全局变量没有反应
浏览器内使用原生websocket接口的测试如下:
let count = 0;
let ws = new WebSocket('ws://localhost:3000/ws/chat');
ws.onopen = function () {
console.log(`[CLIENT] open()`);
ws.send('Hello!');
};
ws.onmessage = function (message) {
console.log(`[CLIENT] Received: ${message}`);
count++;
if (count > 3) {
ws.send('Goodbye!');
ws.close();
} else {
setTimeout(() => {
ws.send(`Hello, I'm Mr No.${count}!`);
}, 1000);
}
};
比如用户登录成功的时候,我会连接上socket服务器,我需要在后台记录当前登录的用户id,所以能不能在websocket连接的时候就能通过req获取到这个用户id
你好 上面的实例一定要使用 VS Code 来开发吗?
如题,按照教程中的代码写法会报错,但是写成 ws.onopen =function(){} 又完全没效果
教材中的API是ws这个包的。在浏览器上用的话是浏览器实现的websockets协议,按照W3C规范。参考这个http://www.runoob.com/html/html5-websocket.html
这一步什么意思,怎么操作直接带过? Error: Cannot find module 'ws'
第一个测试“先在VS Code中执行app.js,或者在命令行用npm start执行。然后,在当前页面下,直接打开可以执行JavaScript代码的浏览器Console,依次输入代码:”Chrome报错为
<code>conn = new WebSocket('ws://localhost:3000');</code> <code>WebSocket {url: "wss://localhost:3000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …} </code> <code>VM557734:1 WebSocket connection to 'wss://localhost:3000/' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED</code> <code>(anonymous) @ VM557734:1</code>
或者 <code>conn = new WebSocket('wss://localhost:3000');</code> <code>WebSocket {url: "wss://localhost:3000/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}</code> <code>VM559283:1 WebSocket connection to 'wss://localhost:3000/' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED</code>
更换为Firefox修改了extension的设置居然就没有报错。 不知道是不是Chrome的SSL安全策略阻止了请求。
WebSocket打不开localhost:3000,页面提示Upgrade Required,response,status返回426.请问该怎么解决!求解答!感谢!
WebSocket connection to 'wss://localhost:55668/test' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED 一看是 wss! 新页面控制台测试正常。
1.1.1的ws在macOSX Sierra上会有bug。。 面向ss编程了半天,一直以为代码哪里出错了。 最后去github看了ws的最新版本3.0.0了,更新之后就ok了。。
wss.on(connection, ) 与 ws.on(open); 是自动触发的,也即新建就立即执行了
var ws=new WebSocket('ws://localhost:3000/test'); ws.onopen=function () { console.log([CLIENT] open()
); ws.send('Hello!'); }; ws.onmessage = function(msg) { console.log(msg); };
如何新建一个vscode工程啊?app.js、package.json都是如何生成的啊?
我说怎么报错:
Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.(…)
加上就成功了
ws.js兼容性如何?
上一节我们用ws
模块创建了一个WebSocket应用。但是它只能简单地响应ECHO: xxx
消息,还属于Hello, world级别的应用。
要创建真正的WebSocket应用,首先,得有一个基于MVC的Web应用,也就是我们在前面用koa2和Nunjucks创建的Web,在此基础上,把WebSocket添加进来,才算完整。
因此,本节的目标是基于WebSocket创建一个在线聊天室。
首先,我们把前面编写的MVC工程复制一份,先创建一个完整的MVC的Web应用,结构如下:
ws-with-koa/
|
+- .vscode/
| |
| +- launch.json <-- VSCode 配置文件
|
+- controllers/ <-- Controller
|
+- views/ <-- html模板文件
|
+- static/ <-- 静态资源文件
|
+- app.js <-- 使用koa的js
|
+- controller.js <-- 扫描注册Controller
|
+- static-files.js <-- 处理静态文件
|
+- templating.js <-- 模版引擎入口
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包
然后,把我们需要的依赖包添加到package.json
:
"dependencies": {
"ws": "1.1.1",
"koa": "2.0.0",
"koa-bodyparser": "3.2.0",
"koa-router": "7.0.0",
"nunjucks": "2.4.2",
"mime": "1.3.4",
"mz": "2.4.0"
}
使用npm install
安装后,我们首先得到了一个标准的基于MVC的koa2应用。该应用的核心是一个代表koa应用的app
变量:
const app = new Koa();
// TODO: app.use(...);
app.listen(3000);
现在第一个问题来了:koa通过3000端口响应HTTP,我们要新加的WebSocketServer还能否使用3000端口?
答案是肯定的。虽然WebSocketServer可以使用别的端口,但是,统一端口有个最大的好处:
实际应用中,HTTP和WebSocket都使用标准的80和443端口,不需要暴露新的端口,也不需要修改防火墙规则。
在3000端口被koa占用后,WebSocketServer如何使用该端口?
实际上,3000端口并非由koa监听,而是koa调用Node标准的http模块创建的http.Server监听的。koa只是把响应函数注册到该http.Server中了。类似的,WebSocketServer也可以把自己的响应函数注册到http.Server中,这样,同一个端口,根据协议,可以分别由koa和ws处理:
把WebSocketServer绑定到同一个端口的关键代码是先获取koa创建的http.Server
的引用,再根据http.Server
创建WebSocketServer:
// koa app的listen()方法返回http.Server:
let server = app.listen(3000);
// 创建WebSocketServer:
let wss = new WebSocketServer({
server: server
});
要始终注意,浏览器创建WebSocket时发送的仍然是标准的HTTP请求。无论是WebSocket请求,还是普通HTTP请求,都会被http.Server处理。具体的处理方式则是由koa和WebSocketServer注入的回调函数实现的。WebSocketServer会首先判断请求是不是WS请求,如果是,它将处理该请求,如果不是,该请求仍由koa处理。
所以,WS请求会直接由WebSocketServer处理,它根本不会经过koa,koa的任何middleware都没有机会处理该请求。
现在第二个问题来了:在koa应用中,可以很容易地认证用户,例如,通过session或者cookie,但是,在响应WebSocket请求时,如何识别用户身份?
一个简单可行的方案是把用户登录后的身份写入Cookie,在koa中,可以使用middleware解析Cookie,把用户绑定到ctx.state.user
上。
WS请求也是标准的HTTP请求,所以,服务器也会把Cookie发送过来,这样,我们在用WebSocketServer处理WS请求时,就可以根据Cookie识别用户身份。
先把识别用户身份的逻辑提取为一个单独的函数:
function parseUser(obj) {
if (!obj) {
return;
}
console.log('try parse: ' + obj);
let s = '';
if (typeof obj === 'string') {
s = obj;
} else if (obj.headers) {
let cookies = new Cookies(obj, null);
s = cookies.get('name');
}
if (s) {
try {
let user = JSON.parse(Buffer.from(s, 'base64').toString());
console.log(`User: ${user.name}, ID: ${user.id}`);
return user;
} catch (e) {
// ignore
}
}
}
注意:出于演示目的,该Cookie并没有作Hash处理,实际上它就是一个JSON字符串。
在koa的middleware中,我们很容易识别用户:
app.use(async (ctx, next) => {
ctx.state.user = parseUser(ctx.cookies.get('name') || '');
await next();
});
在WebSocketServer中,就需要响应connection
事件,然后识别用户:
wss.on('connection', function (ws) {
// ws.upgradeReq是一个request对象:
let user = parseUser(ws.upgradeReq);
if (!user) {
// Cookie不存在或无效,直接关闭WebSocket:
ws.close(4001, 'Invalid user');
}
// 识别成功,把user绑定到该WebSocket对象:
ws.user = user;
// 绑定WebSocketServer对象:
ws.wss = wss;
});
紧接着,我们要对每个创建成功的WebSocket绑定message
、close
、error
等事件处理函数。对于聊天应用来说,每收到一条消息,就需要把该消息广播到所有WebSocket连接上。
先为wss
对象添加一个broadcase()
方法:
wss.broadcast = function (data) {
wss.clients.forEach(function (client) {
client.send(data);
});
};
在某个WebSocket收到消息后,就可以调用wss.broadcast()
进行广播了:
ws.on('message', function (message) {
console.log(message);
if (message && message.trim()) {
let msg = createMessage('chat', this.user, message.trim());
this.wss.broadcast(msg);
}
});
消息有很多类型,不一定是聊天的消息,还可以有获取用户列表、用户加入、用户退出等多种消息。所以我们用createMessage()
创建一个JSON格式的字符串,发送给浏览器,浏览器端的JavaScript就可以直接使用:
// 消息ID:
var messageIndex = 0;
function createMessage(type, user, data) {
messageIndex ++;
return JSON.stringify({
id: messageIndex,
type: type,
user: user,
data: data
});
}
相比服务器端的代码,页面的JavaScript代码会更复杂。
聊天室页面可以划分为左侧会话列表和右侧用户列表两部分:
这里的DOM需要动态更新,因此,状态管理是页面逻辑的核心。
为了简化状态管理,我们用Vue控制左右两个列表:
var vmMessageList = new Vue({
el: '#message-list',
data: {
messages: []
}
});
var vmUserList = new Vue({
el: '#user-list',
data: {
users: []
}
});
会话列表和用户列表初始化为空数组。
紧接着,创建WebSocket连接,响应服务器消息,并且更新会话列表和用户列表:
var ws = new WebSocket('ws://localhost:3000/ws/chat');
ws.onmessage = function(event) {
var data = event.data;
console.log(data);
var msg = JSON.parse(data);
if (msg.type === 'list') {
vmUserList.users = msg.data;
} else if (msg.type === 'join') {
addToUserList(vmUserList.users, msg.user);
addMessage(vmMessageList.messages, msg);
} else if (msg.type === 'left') {
removeFromUserList(vmUserList.users, msg.user);
addMessage(vmMessageList.messages, msg);
} else if (msg.type === 'chat') {
addMessage(vmMessageList.messages, msg);
}
};
这样,JavaScript负责更新状态,Vue负责根据状态刷新DOM。以用户列表为例,HTML代码如下:
<div id="user-list">
<div class="media" v-for="user in users">
<div class="media-left">
<img class="media-object" src="/static/user.png">
</div>
<div class="media-body">
<h4 class="media-heading" v-text="user.name"></h4>
</div>
</div>
</div>
测试的时候,如果在本机测试,需要同时用几个不同的浏览器,这样Cookie互不干扰。
最终的聊天室效果如下:
如果网站配置了反向代理,例如Nginx,则HTTP和WebSocket都必须通过反向代理连接Node服务器。HTTP的反向代理非常简单,但是要正常连接WebSocket,代理服务器必须支持WebSocket协议。
我们以Nginx为例,编写一个简单的反向代理配置文件。
详细的配置可以参考Nginx的官方博客:Using NGINX as a WebSocket Proxy
首先要保证Nginx版本>=1.3,然后,通过proxy_set_header
指令,设定:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Nginx即可理解该连接将使用WebSocket协议。
一个示例配置文件内容如下:
server {
listen 80;
server_name localhost;
# 处理静态资源文件:
location ^~ /static/ {
root /path/to/ws-with-koa;
}
# 处理WebSocket连接:
location ^~ /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 其他所有请求:
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
请问,通过什么方法获取用户的ip呢
参考https://www.npmjs.com/package/ws 和https://github.com/crowbartools/Firebot/issues/526
wss.on('connection', function (ws, req) {
let location = url.parse(req.url, true);
console.log('[WebSocketServer] connection: ' + location.href);
ws.on('message', onMessage);
ws.on('close', onClose);
ws.on('error', onError);
if (location.pathname !== '/:3000/ws/chat') {
// close ws:
ws.close(4000, 'Invalid URL');
}
// check user:
let user = parseUser(req);
if (!user) {
ws.close(4001, 'Invalid user');
}
ws.user = user;
ws.wss = wss;
onConnection.apply(ws);
});
通过加上第二个参数req,可以解决upgradeReq被remove的问题。另外输出发现location.pathname是‘/:3000/ws/chat’而不是‘/ws/chat’,遂也作了替换。
需要删除init-db.js
中的process.exit(0)
,原因我推测是因为前面的数据库操作会耗时,而process.exit(0)
会让程序在数据库操作还未完成的时候就退出了。
init-db.js
这个是需要手动执行的,而且执行的命令是NODE_DEV=test node init-db.js
,这样就设置好了,是在test这个数据库中创建表格。
if (typeof obj === 'string') { s = obj; } else if (obj.headers) { let cookies = new Cookies(obj, null); // 就是这儿 s = cookies.get('name'); }
function onConnect() { let user = this.user; // 为什么不是undefined let msg = createMessage('join', user, ${user.name} joined.
); this.wss.broadcast(msg); // build user list: let users = this.wss.clients.map(function (client) { return client.user; }); this.send(createMessage('list', user, users)); }
使用最新版的ws模块发现ws.upgradeReq.url都是提示url未定义,搜索发现新版ws模块中已经移除了upgradeReq属性,那么替代方案是什么啊,国内根本没找到,国外只找到这个更新说明,文档也没有说代替的方法
ws模块能实现多房间聊天吗,怎么实现多房间聊天呢
vue 在data 里面定义的空数组不是真正的数组,没有length属性,push方法也不能用,大家有没有遇到这样的问题。
function onMessage(message) { console.log(message); if (message && message.trim()) { let msg = createMessage('chat', this.user, message.trim()); //this.wss.broadcast(msg); this.send(msg); } }
这里 this.wss.broadcast(msg); 替换为 this.send(msg);
消息就会值刷新单个页面的
function onConnect() { let user = this.user; let msg = createMessage('join', user, ${user.name} joined.
); this.wss.broadcast(msg); // build user list: let users = this.wss.clients.map(function (client) { return client.user; }); //this.wss.broadcast(createMessage('list', user, users)); this.send(createMessage('list', user, users)); }
这里 his.wss.broadcast(createMessage('list', user, users)); 替换为 this.send(createMessage('list', user, users));
消息就会刷新所有页面的,两句完全相等
app.js: wss.broadcast = function broadcast(data) { wss.clients.forEach(function(client) { client.send(data); }); };
function each(Client) 这个 each 可以省略掉
app.js function onConnect() { let user = this.user; let msg = createMessage('join', user, ${user.name} joined.
); this.wss.broadcast(msg); // build user list: let users = this.wss.clients.map(function (client) { return client.user; }); //this.wss.broadcast(createMessage('list', user, users)); this.send(createMessage('list', user, users)); }
下面这2句是相等的 this.wss.broadcast(createMessage('list', user, users)); this.send(createMessage('list', user, users));
我感觉我的代码已经与廖大大在GitHub上的代码完全一样了,但是我的完全实现不了聊天的功能?图片也加载不出来,信息也发不出去。。。
。。。win10环境 运行demo登录直接Internal Server Error vscode报错 TypeError: this is not a typed array. 求解
win环境下运行项目时,多出出现这种报错,
E:\WEB TEST\test\nodeLearnDemo3\controllers\signin.js:10
let names = '甲乙丙丁戊己庚辛壬癸';
^^^
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
多方查阅之后,发现是文件的的开头未添加"use strict";
在此评论一下,为后面的初学者提个醒,不然真的会找很久找不到原因的呢 /(ㄒoㄒ)/~~
为什么匿名函数不使用箭头函数的形式呢?而是大量使用了function(){}的形式。
表示原来只听说过,并没有用过啊
来自 https://www.liaoxuefeng.com/wiki/1022910821149312/1103332447876608
好奇
在线炒股为什么不鼓励
全部讨论 回复
峰哥。问一个问题。
我的项目按照写个。测试也联通了。是一个关于交响乐的私人项目。里面包含一个网页播放器页面。一个专辑页面。现在遇到一个问题。点击专辑页面的播放按钮后如何在后台将这个推到播放器页面。由于跨越了view。我想了很多办法。多线程。异步回调等等都没有解决问题。就想问问峰哥有什么好的建议或者方法。
全部讨论 回复
用javaEE实现的websocket
厉害啊 ,学习了
厉害厉害,刚好java socket这块一直懵懵懂懂,ssm倒是常用,学起来应该没多大问题,感谢分享
您好 廖老师 谢谢您的分享。 在原文中——"首先,"wss:// xxx创建WebSocket连接时," 是不是应该为 ws:// 谢谢
上面那位,仔细看教程,廖老师说的是安全的
WebSocket
连接全部讨论 回复