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

Angular CLI/Angular 4与Python Tornado等后端框架的协作及数据交互咨询

Hey there! I totally get how frustrating it can be to untangle how Angular 4 (built with Angular CLI) works with a Python backend like Tornado, especially after days of searching and not quite connecting the dots. Let’s walk through this with practical, easy-to-follow examples so you can see the full picture.

Core Architecture Overview

First, let’s set the baseline: we’re using a separated frontend-backend setup. The Angular 4 app handles all UI rendering, user interactions, and client-side logic, while the Python backend (Tornado in our case) manages data storage, business logic, and exposes APIs for the frontend to talk to.

"Two-way data transfer" here usually means three key scenarios:

  1. Frontend fetches data from the backend (e.g., loading a list of users)
  2. Frontend sends data to the backend (e.g., submitting a form)
  3. For real-time updates (like chat or live notifications), we’ll use WebSockets to let the backend push data to the frontend without waiting for a request.

Step 1: Spin Up Your Angular 4 Project (Angular CLI)

First, make sure you have the right Angular CLI version for Angular 4:

npm install -g @angular/cli@1.4.9

Then create your project and start the dev server:

ng new angular-tornado-demo
cd angular-tornado-demo
ng serve

You should see the default Angular page at http://localhost:4200—confirm it’s working before moving on.


Step 2: Build a Simple Tornado Backend

First install Tornado via pip:

pip install tornado

Create a file named server.py with this code—it sets up basic REST APIs and a WebSocket endpoint for real-time communication:

import tornado.ioloop
import tornado.web
import tornado.websocket
import json

# In-memory "database" for demo purposes (replace with a real DB in production)
users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
active_websockets = set()

class UserHandler(tornado.web.RequestHandler):
    def set_default_headers(self):
        # Handle CORS (cross-origin requests) since Angular runs on a different port
        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
        self.set_header("Access-Control-Allow-Headers", "Content-Type")

    def options(self):
        # Respond to preflight requests required for CORS
        self.set_status(204)
        self.finish()

    def get(self):
        # Return all users as JSON
        self.write(json.dumps(users))

    def post(self):
        # Add a new user from frontend-submitted data
        new_user = json.loads(self.request.body)
        new_user["id"] = len(users) + 1
        users.append(new_user)
        self.write(json.dumps({"success": True, "user": new_user}))

class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def open(self):
        active_websockets.add(self)
        print("New WebSocket connection established")

    def on_message(self, message):
        # Broadcast incoming message to all connected clients
        data = json.loads(message)
        for ws in active_websockets:
            ws.write_message(json.dumps({"from": "backend", "message": f"Received: {data['message']}"}))

    def on_close(self):
        active_websockets.remove(self)
        print("WebSocket connection closed")

def make_app():
    return tornado.web.Application([
        (r"/api/users", UserHandler),
        (r"/api/ws", WebSocketHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    print("Tornado server running on http://localhost:8888")
    tornado.ioloop.IOLoop.current().start()

Run the backend server:

python server.py

Step 3: Connect Angular 4 to the Backend

Let’s add code to Angular to interact with our Tornado APIs.

3.1 Fetch Data from Backend (GET Request)

First, enable HTTP support in Angular by importing HttpClientModule in src/app/app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http'; // Add this line

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule // Add this to imports
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Create a service to handle API calls:

ng generate service user

Update src/app/user.service.ts with methods to fetch and add users:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class UserService {
  private apiUrl = 'http://localhost:8888/api/users';

  constructor(private http: HttpClient) { }

  // Fetch all users from backend
  getUsers(): Observable<any[]> {
    return this.http.get<any[]>(this.apiUrl);
  }

  // Send new user data to backend
  addUser(user: any): Observable<any> {
    return this.http.post<any>(this.apiUrl, user);
  }
}

Now use this service in src/app/app.component.ts to load users when the component initializes:

import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  users: any[] = [];
  newUserName = '';

  constructor(private userService: UserService) { }

  ngOnInit() {
    // Fetch users when component loads
    this.userService.getUsers().subscribe(users => {
      this.users = users;
    });
  }
}

Update src/app/app.component.html to display the user list:

<h1>User List</h1>
<ul>
  <li *ngFor="let user of users">{{ user.id }} - {{ user.name }}</li>
</ul>

Refresh your Angular page—you should see Alice and Bob listed!

3.2 Send Data to Backend (POST Request)

Add a form to app.component.html to submit new users:

<h2>Add New User</h2>
<input type="text" [(ngModel)]="newUserName" placeholder="Enter user name">
<button (click)="addUser()">Add User</button>

Add the addUser method to app.component.ts:

addUser() {
  if (!this.newUserName.trim()) return;
  this.userService.addUser({ name: this.newUserName }).subscribe(response => {
    this.users.push(response.user);
    this.newUserName = ''; // Clear input field
  });
}

Don’t forget to import FormsModule in app.module.ts to use [(ngModel)]:

import { FormsModule } from '@angular/forms'; // Add this line

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule // Add to imports
  ],
  // ... rest of the code
})

Now when you enter a name and click "Add User", the data is sent to Tornado, stored in our in-memory list, and the new user appears on the page instantly.

3.3 Real-Time Two-Way Communication (WebSocket)

Let’s add WebSocket support for real-time updates. Update app.component.ts:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {
  users: any[] = [];
  newUserName = '';
  ws: WebSocket | null = null;
  messageInput = '';
  messages: string[] = [];

  constructor(private userService: UserService) { }

  ngOnInit() {
    this.userService.getUsers().subscribe(users => {
      this.users = users;
    });

    // Initialize WebSocket connection
    this.ws = new WebSocket('ws://localhost:8888/api/ws');
    this.ws.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.messages.push(data.message);
    };
  }

  sendMessage() {
    if (!this.messageInput.trim() || !this.ws) return;
    this.ws.send(JSON.stringify({ message: this.messageInput }));
    this.messageInput = '';
  }

  ngOnDestroy() {
    // Clean up WebSocket connection when component is destroyed
    if (this.ws) {
      this.ws.close();
    }
  }

  addUser() {
    // ... existing addUser code
  }
}

Add a real-time chat section to app.component.html:

<h2>Real-Time Chat</h2>
<input type="text" [(ngModel)]="messageInput" placeholder="Type a message">
<button (click)="sendMessage()">Send</button>
<ul>
  <li *ngFor="let msg of messages">{{ msg }}</li>
</ul>

Open two browser tabs with your Angular app—when you send a message, both tabs will receive the backend’s response in real time.


Handling CORS (Optional but Cleaner)

In our Tornado code, we added CORS headers to allow requests from Angular’s port. Alternatively, you can use Angular CLI’s proxy to avoid CORS issues entirely:

  1. Create proxy.conf.json in your Angular project root:
{
  "/api/*": {
    "target": "http://localhost:8888",
    "secure": false,
    "changeOrigin": true
  }
}
  1. Update the serve command in angular.json to use the proxy:
"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "options": {
    "browserTarget": "angular-tornado-demo:build",
    "proxyConfig": "proxy.conf.json"
  },
  // ... rest of the code
}
  1. Now you can change apiUrl in user.service.ts to /api/users (no full URL needed), and Angular CLI will forward requests to Tornado automatically.

What About Other Python Frameworks?

If you switch to Flask or Django, the core logic stays identical:

  • Flask: Use Flask-RESTful or plain routes to expose JSON APIs, handle CORS with flask-cors.
  • Django: Use Django REST Framework to build APIs, set up CORS with django-cors-headers.
    Angular will interact with these backends the exact same way—via HTTP requests or WebSockets.

内容的提问来源于stack exchange,提问作者Xingsong Lin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:12:00