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

Json Server发起PUT/PATCH请求返回404,GET请求正常

问题描述

在浏览器端通过组件内输入控件修改从服务端获取的skills: SkillSet[]类型数据,计划通过两个按钮控制是否将变更同步更新到服务端,但saveChanges函数始终无法正常运行。

Skills组件的saveChanges函数代码如下:

saveChanges(): void {
    this.editMode = false;
    this.skillsService.saveChanges(this.skills).subscribe();
  }

Skills服务的saveChanges函数代码如下:

// Update changes made by the component
  saveChanges(skills: SkillSet[]): Observable<SkillSet[]> {
    console.log(skills); // 控制台打印可以证明数组已经携带了编辑后的内容
    return this.http.patch<SkillSet[]>(
      this.skillsUrl,
      skills,
      this.httpOptions
    );
  }

点击触发按钮后,控制台返回错误:PATCH http://localhost:5000/skills 404 (Not Found),改用PUT方法请求同样报错。但该URL的GET请求可以正常访问,页面初始加载时能正常获取模板渲染所需数据。


完整相关代码

SkillSet接口定义

export interface SkillSet {
  id: number;
  type: string;
  title: string;
  description: string;
  tools: string[];
}

Skills组件完整代码

import { Component, OnInit } from '@angular/core';

import { SkillSet } from 'src/app/interfaces/skill-set';
import { SkillsService } from 'src/app/services/skills.service';

@Component({
  selector: 'app-skills',
  templateUrl: './skills.component.html',
  styleUrls: ['./skills.component.scss'],
})
export class SkillsComponent implements OnInit {
  login: boolean = true;
  editMode: boolean = false;

  skills: SkillSet[] = [];
  newTool: string = '';

  constructor(private skillsService: SkillsService) {}

  ngOnInit(): void {
    this.getSkills();
  }

  getSkills() {
    this.skillsService
      .getSkills()
      .subscribe((skills) => (this.skills = skills));
  }

  // 板块编辑功能函数
  addTool(skillSet: SkillSet, tool: string) {
    if (tool) {
      skillSet.tools.push(tool);
    }
  }
  deleteTool(skillSet: SkillSet, tool: string) {
    skillSet.tools = skillSet.tools.filter((t) => t !== tool);
  }

  // 变更操作菜单
  editStart() {
    this.editMode = true;
    console.log('Editing skills');
  }
  saveChanges(): void {
    this.editMode = false;
    this.skillsService.saveChanges(this.skills).subscribe();
  }
  cancelChanges() {
    this.editMode = false;
    this.getSkills();
  }
}

Skills服务完整代码

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Observable, of } from 'rxjs';

import { SkillSet } from '../interfaces/skill-set';

@Injectable({
  providedIn: 'root',
})
export class SkillsService {
  private skillsUrl = 'http://localhost:5000/skills';

  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json',
    }),
  };

  constructor(private http: HttpClient) {}

  getSkills(): Observable<SkillSet[]> {
    return this.http.get<SkillSet[]>(this.skillsUrl);
  }

  // 同步组件端的修改到服务端
  saveChanges(skills: SkillSet[]): Observable<SkillSet[]> {
    console.log(skills); // 控制台打印可证明数组已携带编辑后内容
    return this.http.patch<SkillSet[]>(
      this.skillsUrl,
      skills,
      this.httpOptions
    );
  }
}

问题原因与解决方案

核心原因

GET请求/skills路径正常但PATCH/PUT返回404,和前端代码无关,是后端接口路由没有配置对应路径的PATCH/PUT方法导致的:

  • 你当前后端只给/skills路径配置了GET方法,用于获取全量技能列表,所以页面初始化加载数据正常
  • RESTful接口规范中,批量更新全量列表、单条资源更新的路径是不一样的:
    • 单条资源更新:PATCH/PUT /skills/{资源id},需要携带对应单条SkillSet的id和修改内容
    • 全量列表批量替换:PUT /skills,需要后端单独实现该路径的PUT方法逻辑
    • 批量部分更新:PATCH /skills,同样需要后端单独实现对应方法逻辑

修复步骤

  • 先确认你的后端服务(看端口5000大概率是json-server或者Node/Flask/Django类服务)的接口配置:
    • 如果用的是json-server:默认不支持直接对列表根路径发PATCH/PUT批量更新,要么循环单条调用/skills/{id}的PATCH接口更新每一项,要么自定义路由添加批量更新逻辑
    • 如果是自己写的后端服务:给/skills路径添加PUT/PATCH方法的处理逻辑,或者调整前端逻辑为遍历修改过的SkillSet项,逐个调用单条更新接口
  • 前端代码对应调整(以后端支持单条更新为例):
    先在service里添加单条更新方法:
    updateSkill(skill: SkillSet): Observable<SkillSet> {
      const url = `${this.skillsUrl}/${skill.id}`;
      return this.http.patch<SkillSet>(url, skill, this.httpOptions);
    }
    
    再修改组件里的saveChanges方法,用forkJoin并行提交所有更新:
    // 记得在组件顶部导入forkJoin:import { forkJoin } from 'rxjs';
    saveChanges(): void {
      this.editMode = false;
      const updateTasks = this.skills.map(skill => this.skillsService.updateSkill(skill));
      forkJoin(updateTasks).subscribe({
        next: () => console.log('所有修改已同步'),
        error: err => console.error('同步失败', err)
      });
    }
    
  • 如果需要做批量更新,就先在后端实现/skills路径的PATCH/PUT处理逻辑,再保留你当前前端的写法即可。

额外排查点:如果是本地开发跨域场景,检查后端是否配置了对应请求方法的CORS放行规则,OPTIONS预检请求失败也会返回404类错误,但你GET请求正常的话这个概率很低。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 12:57:12