- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我使用 symfony 2 开发了一个网站。直到现在它还没有使用ajax。当您发布新评论时,页面已刷新。
我添加了一个 ajax 层,因此无需刷新即可提交表单。
每次我发布新帖子时,我都希望允许所有在线用户在他们的时间线中看到这篇帖子。
这就是我现在所做的:
我创建了一个事件 NewPostAdded 和一个订阅者渲染到 html 帖子(希望我将它发送给客户端并且客户端将 $('.timeline').prepend(post) )
我正在寻找一种方法来实现将启动 websocket 服务器的 symfony2 命令。我的订户将能够将帖子+数据(它是公开的吗?否则允许查看它的用户 ID 列表)推送到此服务器。然后,该服务器将有一个在线用户列表,如果该帖子是公开的,它将推送给其他所有人,并将其推送给正确的在线用户。
我在使用 symfony 2.1 + redis + nodejs + socket.io 之前已经这样做了,但它显然无法维护,而且由于这个网站不是针对大量观众的,所以我想保持简单。
这是我的第二个问题:
是否有一个 bundle 使思考变得简单,提供了一种简单的方式来编写带有收入事件监听器(从 symfony 接收帖子)和事件发送器(向用户发送帖子)的服务器,添加事件监听器客户端(准备好使用 Assets 添加以能够对客户端进行编码)对服务器消息使用react?
有没有办法在客户端使用除用户 ID 之外的其他东西来“验证”websocket 服务器上的用户,以避免用户更改客户端代码中的 ID 以接收他们不应该查看的帖子?
最佳答案
是的,你可以使用 php web socket Ratchet "http://socketo.me/ ",你可以将它用作 composer 包 https://packagist.org/packages/cboden/ratchet
您应该创建一个服务应用程序,然后您应该创建一个将运行套接字应用程序的控制台命令。
您应该生成一个 secret token ,例如 userId 的 md5 散列 + 一些将用于检查套接字连接是否可信的 secret key ,而不是 userId。
更新:
Composer .json
...
"cboden/ratchet": "0.3.*",
...
然后你应该创建一个新的包,假设是“WebSocketBundle”
namespace MyApp\WebSocketBundle\WebSocket;
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
class WebSocketApplication implements MessageComponentInterface
{
protected $container;
protected $clients;
protected $redis;
public function __construct($container)
{
$this->clients = [];
$this->container = $container;
$this->redis = $container->get('snc_redis.something'); // your redis service
}
public function onMessage(ConnectionInterface $from, $msg)
{
$messageData = $this->decodeJSONAndCheckMessage($from, $msg);
// here you must pass a token in messageData and implement own function to check is the token valid
$loginResult = $this->userLogin($from, $messageData);
if ($loginResult instanceof Success) { // my custom success class message
$this->handleMessage($from, $messageData);
} else {
$this->onError($from, new \Exception('Cannot login a user.'));
}
}
// some strategy wrapper
private function handleMessage($from, $messageData)
{
$message = $messageData->message;
if (method_exists($this, $message)) {
try {
$this->$message($from, $messageData);
} catch (Exception $ex) {
$this->onError($from, $ex);
}
} else {
$this->onError($from, new \Exception(sprintf('Unknown method "%s"', $message)));
}
}
// you can use here post new message action
private function eventStartSomething($from, $messageData)
{
if (!$messageData->somethingId) {
$this->onError($from, new \Exception('Bad parameters'));
return;
}
$scope = [];
$scope['clients'][$from->resourceId] = null;
// I need socket for something only limited amount of time, you can implement here own logic
$this->redis->setex($messageData->somethingId, 600, serialize($scope));
$this->clients[$from->resourceId]['scope'] = $messageData->eventId;
$this->logMessage($from, 'started new something with Id: ' . $messageData->somethingId);
$from->send($this->getResultOKMessage());
}
private function eventGetSomething($from, $messageData)
{
$scopeKey = $this->redis->get($messageData->somethingId);
if (!$scopeKey) {
$this->onError($from, new \Exception('Bad or expired something ' . $messageData->somethingId));
return;
}
if (!$this->checkForClientInScope($from->resourceId, $messageData->eventId)) {
if ($this->assignClientToScope($from->resourceId, $messageData->eventId)) {
$this->sendMessageToScope($from, $messageData->eventId, $this->getScopeWatchMessage($from, $messageData->eventId));
$from->send($this->getScopeWatchMessage($from, $messageData->eventId));
}
}
}
private function assignClientToScope($clienResourseId, $scopeId)
{
$result = false;
$scopeKey = $this->redis->get($scopeId);
if (!$scopeKey) {
return $result;
}
$scope = unserialize($scopeKey);
if (!array_key_exists($clienResourseId, $scope['clients'])) {
// I need socket for something only limited amount of time, you can implement here own logic
$this->redis->setex($scopeId, 600, serialize($scope));
if (array_key_exists($clienResourseId, $this->clients)) {
$this->clients[$clienResourseId]['scope'] = $scopeId;
}
$result = true;
}
return $result;
}
private function sendMessageToScope($from, $scopeId, $message)
{
$scopeKey = $this->redis->get($scopeId);
if (!$scopeKey) {
$this->onError($from, new \Exception('Bad or expired event ' . $scopeId . ' for sending message'));
return;
}
$scope = unserialize($scopeKey);
foreach ($scope['clients'] as $clientResourceId => $remoteAddress) {
if (array_key_exists($clientResourceId, $this->clients) &&
$this->clients[$clientResourceId]['connection'] != $from) {
$this->clients[$clientResourceId]['connection']->send($message);
}
}
}
public function onClose(ConnectionInterface $conn)
{
if (isset($this->clients[$conn->resourceId]['scope'])) {
$scopeId = $this->clients[$conn->resourceId]['scope'];
$this->removeClientFromScope($conn->resourceId);
$this->sendMessageToScope($conn, $scopeId, $this->getScopeWatchMessage($conn, $scopeId));
}
unset($this->clients[$conn->resourceId]);
$this->logMessage($conn, 'Connection closed.');
}
public function onError(ConnectionInterface $conn, \Exception $e)
{
echo date("Y-m-d H:i:s") . ":" . "WebSocket error::" . $e->getMessage() . " resourceId:" . $conn->resourceId . ". remoteAddress:" . $conn->remoteAddress . "\n";
$conn->send($this->getErrorMessage($e->getMessage()));
}
public function onOpen(ConnectionInterface $conn)
{
$this->clients[$conn->resourceId]['connection'] = $conn;
$this->logMessage($conn, 'New connection.');
}
}
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Snc\RedisBundle\Session\Storage\Handler\RedisSessionHandler;
use Ratchet\Session\SessionProvider;
use MyApp\WebSocketBundle\WebSocket\WebSocketApplication;
class ListenCommand extends ContainerAwareCommand
{
protected function configure()
{
$this->setName('myapp:websocket:listen')
->setDescription('Listen for websocket requests ')
->addOption('port', 'p', InputOption::VALUE_REQUIRED, 'The port to listen on', 8000)
->addOption('interface', 'i', InputOption::VALUE_REQUIRED, 'The interface to listen on', '0.0.0.0');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$redis = $this->getContainer()->get('snc_redis.default');
$application = new WebSocketApplication($this->getContainer());
$server = IoServer::factory(
new HttpServer(
new WsServer(
new SessionProvider(
$application,
new RedisSessionHandler($redis)
)
)
),
$input->getOption('port'),
$input->getOption('interface')
);
echo "Listening on: ".$input->getOption('interface').":".$input->getOption('port')."\n";
$server->run();
}
}
关于javascript - 有没有一种干净的方法可以使用 symfony 2.6 设置 websocket,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30290034/
我刚刚开始使用 javascript,多年来一直使用 C# 和 OO 语言。 我发现我将我的代码放在这样的文件中, database.js sync.js date.js 而且感觉非常程序化,基本上就
当我运行 git clean --dry-run 时,结果有点像: Would remove an_untracked_file Would remove an_untracked_file_2 Wo
嘿,第一次在 Stack Overflow 上提问,所以请放轻松! 我最近开始开发一个 CMS 驱动的网站,该网站需要多语言功能(12 种语言!)。我过去曾推出过 Expression Engine/
我正在使用可移植类库构建 Android/iOS xamarin 表单应用程序。我正在寻找在 PCL 项目中执行此示例的最佳方法: https://msdn.microsoft.com/en-us/l
我经常听到有关"new"MV* 框架的信息。我修改了 KnockoutJS,创建了一个发票应用程序,但我更喜欢用原始 JavaScript 编写干净、模块化的代码——必要时利用实用程序 API 和其他
我有这段 javascript 代码,当我点击按钮时, Canvas 会被清除。 但是当我移动鼠标时, Canvas 会显示我之前写的内容,而且它不会以空白 Canvas 开始 单击按钮后如何从空白
我有一个带有 5 个内部字符串变量的对象,但其中 3 个是可选的。我可以为每个可能的组合创建一个构造函数,或者我可以调用通用构造函数并向其传递一些空字符串。后一种情况对我来说很有趣,如果我在调用构造函
我是 SQL 的新手。我正在尝试从数据库 (Postgres) 获取数据,如果这些数据无效,则即时替换它们。是否可以使用纯 SQL 来执行此操作?例如,在我的数据库 users 中,我有包含以下数据的
当我清理 TOMCAT 或清理 tomcat 工作目录时,我丢失了保存在 Tomcat 文件夹中的所有文件,我可以禁用此选项吗? 最佳答案 清理 tomcat 工作目录将清除部署到 Tomcat 中的
我正在清理我的一个旧项目。它必须做的一件事是——给定笛卡尔网格系统和网格上的两个正方形,找到所有正方形的列表,连接这两个正方形中心的线将通过这些正方形。 这里的特殊情况是所有起点和终点都被限制在正方形
我现在正在学习如何使用 makefile 并制作了以下 makefile(我在 Windows 上使用 visual studio 命令行编译器) CC = cl CFLAG = /EHsc test
我做了 git checkout master。如果我执行 git status 它会在我的工作目录中显示两个更改的文件,即使我没有碰过它们。这似乎是某种行尾问题。 git reset --hard
在我看来,Makefile 规则大致可以分为“积极”和“消极”规则:“积极”规则创建丢失或更新过时的文件,而“消极”规则删除文件。 为“肯定”规则编写先决条件非常简单:如果目标和先决条件是文件名,ma
我的电脑上安装了 WAMP,我想在其中运行 Drupal 6。 当我安装 Drupal 时,我可以选择激活 Clean URL。 首先,我将 Drupal 安装放在 www 文件夹中,我可以选择启用干
考虑以下堆栈跟踪: In [3]: f.clean() ------------------------------------------------------------------------
我放弃了。我已经阅读了这里的几十个问题,甚至问了我自己的问题,我尝试了很多事情,我只是不知道该怎么做。 我需要使用以下格式创建 url:(NSFW 链接,请注意) http://jbthehot.co
下面的代码是我目前的解决方案。 我试图模仿的一个很好的例子是 FrameworkElement.ActualWidth 属性。您知道 ActualWidth 属性是如何计算和重新分配的,每当 Widt
当然,Ruby 确实有递归,就像任何其他高级编程语言一样。只要递归深度不是太高,这就可以正常工作,但如果是,您将捕获堆栈溢出: #!/usr/bin/ruby2.0 def rec_naive(i)
我找到的最短方法是: n = 5 # Python 2. s = str(n) i = int(s) # Python 3. s = bytes(str(n), "ascii") i = int(s)
这是一种经常出现的情况,对我来说永远不会太容易。我想我会问其他人如何处理它。 想象一下,如果 demo=60 命令行参数的处理是这样完成的: if DemoOptionSpecified() {
我是一名优秀的程序员,十分优秀!