You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular需配置app.get("*",[...]);才能运行,SSH关机功能开发求助

Hey there! Let's break down your two issues one by one—they're both common hurdles when building full-stack Angular + Express apps, so you're in good company.

1. Why Angular requires app.get("*", ...) in Express

Angular is a single-page application (SPA)—all your frontend routing happens client-side, not on the server. When you visit a direct URL like /dashboard or /settings (instead of starting at the root /), your Express server doesn't recognize those routes by default. It would normally throw a 404 error because it only knows about the API endpoints you've defined.

The app.get("*", ...) rule acts as a catch-all: it tells Express to send your Angular index.html file for any request that isn't matched by an existing API route. This lets Angular take over and handle the client-side routing correctly.

Correct Order Matters!

Make sure you define all your API routes before the catch-all rule. If you put the catch-all first, your API requests will get redirected to index.html instead of hitting your endpoints. Here's a typical setup:

const express = require('express');
const path = require('path');
const app = express();

// First: Define your API routes
app.get('/api/status', (req, res) => {
  res.json({ status: 'running' });
});

// Then: Serve Angular's static files (CSS, JS, assets)
app.use(express.static(path.join(__dirname, 'dist/your-angular-app')));

// Finally: Catch-all route for Angular client-side routing
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/your-angular-app/index.html'));
});

app.listen(3000, () => console.log('Server running on port 3000'));
2. Server-side SSH Shutdown Implementation

You're absolutely right to avoid handling SSH directly in browser scripts—it's a huge security risk (you'd expose credentials or private keys to the client). Instead, we'll build an Express endpoint that acts as a secure middleman to execute the shutdown command via SSH.

Step 1: Use a Node.js SSH Library

We'll use the ssh2 package (a popular, robust SSH client for Node.js). Install it first:

npm install ssh2

Step 2: Build the Secure Express Endpoint

Create a POST endpoint that:

  • Verifies the user is authorized (e.g., checks for a valid admin session token—never let unauthenticated users call this!)
  • Establishes an SSH connection to your ownCloud server
  • Executes the graceful shutdown command
  • Returns a success/error response to the Angular frontend

Here's a sample implementation:

const { Client } = require('ssh2');

// Store SSH credentials securely (use environment variables, not hardcoded!)
const SSH_CONFIG = {
  host: process.env.SSH_SERVER_HOST,
  port: process.env.SSH_SERVER_PORT || 22,
  username: process.env.SSH_USERNAME,
  // Use either password or private key (private key is more secure)
  password: process.env.SSH_PASSWORD,
  // privateKey: require('fs').readFileSync('/path/to/private/key')
};

// Admin-only shutdown endpoint
app.post('/api/server/shutdown', (req, res) => {
  // First: Add your auth check here (e.g., verify req.user is admin)
  // Example: if (!req.user || !req.user.isAdmin) return res.status(403).send('Unauthorized');

  const conn = new Client();
  conn.on('ready', () => {
    console.log('SSH connection ready');
    // Execute graceful shutdown command (adjust based on your OS)
    conn.exec('shutdown -h now', (err, stream) => {
      if (err) {
        conn.end();
        return res.status(500).json({ error: `Failed to execute shutdown: ${err.message}` });
      }
      stream.on('close', (code, signal) => {
        conn.end();
        if (code === 0) {
          res.json({ success: true, message: 'Shutdown command sent successfully' });
        } else {
          res.status(500).json({ error: `Shutdown command exited with code ${code}` });
        }
      }).on('data', (data) => {
        console.log(`SSH stdout: ${data}`);
      }).stderr.on('data', (data) => {
        console.error(`SSH stderr: ${data}`);
      });
    });
  }).on('error', (err) => {
    res.status(500).json({ error: `SSH connection failed: ${err.message}` });
  }).connect(SSH_CONFIG);
});

Step 3: Connect Angular Frontend to the Endpoint

In your Angular component, add a button that calls this endpoint via HttpClient. Make sure to handle loading states and error messages:

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

@Component({
  selector: 'app-server-controls',
  template: `
    <button (click)="shutdownServer()" [disabled]="isLoading">
      {{ isLoading ? 'Shutting down...' : 'Stop Server' }}
    </button>
    <div *ngIf="errorMessage" class="text-danger">{{ errorMessage }}</div>
  `
})
export class ServerControlsComponent {
  isLoading = false;
  errorMessage = '';

  constructor(private http: HttpClient) {}

  shutdownServer() {
    this.isLoading = true;
    this.errorMessage = '';
    this.http.post('/api/server/shutdown', {})
      .subscribe({
        next: (res: any) => {
          this.isLoading = false;
          // Show success message to user
          alert(res.message);
        },
        error: (err) => {
          this.isLoading = false;
          this.errorMessage = err.error?.error || 'Failed to shut down server';
        }
      });
  }
}

Critical Security Notes

  • Never hardcode credentials: Use environment variables (e.g., dotenv package) or a secure secrets manager.
  • Add authentication: Only allow authenticated admin users to access this endpoint—use sessions, JWT tokens, or OAuth to verify user permissions.
  • Limit command scope: Avoid allowing arbitrary command execution; hardcode the shutdown command instead of accepting user input.
  • Handle errors gracefully: Return clear error messages to the frontend without exposing sensitive server details.

内容的提问来源于stack exchange,提问作者C. Dautermann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:57:52