You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Express Node.js API中读取请求参数?Angular5调用疑难

解决Express API读取查询字符串参数及Angular商品详情展示问题

看起来你卡在了Express中获取查询参数、无法从MongoDB拿到对应商品数据的环节。咱们一步步排查并解决这个问题:

1. 核心问题分析

你的Express路由里req.query.ProductId的写法本身是正确的,但可能存在以下几个小问题:

  • 请求参数的大小写不匹配(URL查询参数区分大小写)
  • CORS头设置顺序错误,可能影响响应正常返回
  • 缺少调试日志,无法确认参数是否真的传递到了API
  • MongoDB连接未正确关闭,可能导致资源泄漏

2. 修正后的Express代码(server.js)

var express = require('express');
var mongodb = require('mongodb').MongoClient;
var app = express();
var port = process.env.PORT||3000;
var commanRouter = express.Router();

// 全局设置CORS,避免每个路由重复编写
app.use(function(req, res, next) {
  res.setHeader('Access-Control-Allow-Origin','*');
  res.setHeader('Access-Control-Allow-Headers','Origin,X-Requested-With,Content-Type,Accept');
  next();
});

commanRouter.route('/getPrdDetails')
.get(function(req,res){
  // 调试日志:打印所有查询参数,确认是否收到ProductId
  console.log('Received query parameters:', req.query);
  
  // 关键:根据MongoDB中ProductId的类型转换参数
  // 如果数据库中是数字类型,用Number()转换;如果是字符串则直接使用
  let prdId = Number(req.query.ProductId); 
  
  var url = 'mongodb://xyz:xyz@ds127536.mlab.com:27536/dbxyz';
  mongodb.connect(url, (err, client) => { // 新版MongoDB驱动用client代替旧的db对象
    if (err) {
      console.log(err);
      return res.status(500).send('Database connection error');
    }
    let mydb = client.db("dbxyz");
    let queryM = {"ProductId": prdId};
    mydb.collection('products').find(queryM).toArray( function(err,data){
      client.close(); // 查询完成后关闭数据库连接,避免资源泄漏
      if(err) {
        return res.status(500).send(err);
      }
      res.json(data);
    });
  });
});

app.use('/api', commanRouter);

app.get('/',function(req,res){
  res.send("Working");
});

app.use(express.static(__dirname + '/public'));

app.listen(port, function(){
  console.log("Server running on port", port);
});

关键修改点:

  • 全局CORS设置:把CORS头放到全局中间件,确保响应发送前已完成设置,避免跨域问题
  • 调试日志:添加console.log确认查询参数是否正确传递到API
  • 参数类型转换req.query中的参数默认是字符串,根据MongoDB中ProductId的类型做转换,避免查询不匹配
  • MongoDB连接优化:使用新版驱动的client对象,并在查询完成后关闭连接,防止资源泄漏

3. Angular端的小优化建议

你的Angular代码逻辑没问题,但可以添加调试和规范参数传递的优化:

product-details.component.ts 优化

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ProductService } from './product.service';
import { IProduct } from './product';

@Component({
  templateUrl:'./product-details.component.html',
  styleUrls:['./product-details.component.css']
})
export class ProductDetailsComponent{
  products:IProduct[];
  errorMessage:string;
  pId:number;

  constructor(
    private _route:ActivatedRoute, 
    private _productService:ProductService
  ){}

  ngOnInit():void{
    console.log("<<<<<<<<---------------------This is Product-Details:Init-------------------------->>>>>>>>");
    // 确保路由参数转为数字类型,避免传递字符串给API
    let id = Number(this._route.snapshot.params['id']);
    this.pId = id;
    console.log('Fetching product details for ID:', id); // 调试日志
    
    this._productService.getProductDetails(id)
      .subscribe(
        products => {
          this.products = products;
          console.log('Received product data:', products); // 调试日志
        },
        error => {
          this.errorMessage = <any>error;
          console.error('Error fetching product details:', error); // 调试日志
        }
      );
  }
}

product-details.service.ts 优化

import { Injectable } from '@angular/core';
import { Http, Response, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { IProduct } from './product';

@Injectable() 
export class ProductService{
  private _prdDetailsUrl= "https://abc-xyz-12345.herokuapp.com/api/getPrdDetails";

  constructor(private _http:Http){ }

  getProductDetails(productId:number):Observable<IProduct[]>{
    // 用URLSearchParams构建查询参数,比字符串拼接更规范,避免特殊字符问题
    const params = new URLSearchParams();
    params.set('ProductId', productId.toString());
    return this._http.get(this._prdDetailsUrl, { search: params })
      .map((response:Response)=><IProduct[]>response.json())
      .catch(this.handleError);
  }

  private handleError(error:Response){
    console.error('API Error:', error);
    return Observable.throw(error.json().error || "Server Error!");
  }
}

Angular端关键优化:

  • 类型确保:把路由参数转为数字,避免传递字符串导致API查询不匹配
  • 调试日志:添加日志跟踪参数传递和数据接收情况,方便排查问题
  • 规范参数构建:用URLSearchParams构建查询参数,比直接字符串拼接更可靠

4. 调试步骤

  1. 启动Express服务器后,直接在浏览器访问http://localhost:3000/api/getPrdDetails?ProductId=1008,验证API是否能返回正确数据
  2. 打开浏览器开发者工具的Network标签,查看Angular发送的请求,确认查询参数ProductId是否正确携带
  3. 查看Express服务器的控制台日志,确认req.query里是否包含ProductId

按这个流程排查,应该就能解决你无法获取商品详情的问题了。

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

火山引擎 最新活动