关于访问后端接口报404的问题——全网最详细的404错误详解

Posted keep thinking

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于访问后端接口报404的问题——全网最详细的404错误详解相关的知识,希望对你有一定的参考价值。

当我们通过前端向后端发起一个请求调用后端接口时,经常会遇到404的问题。网上关于对404问题介绍的一大堆,其实404问题的本质就两点。

在介绍404问题之前先温习一个小的知识点——项目访问路径
项目访问路径:就是定位一个项目的路径,可以理解为项目名,但是一般这个名称是可以自定义的。在SpringBoot在2.0版本之前,在yml文件中配置项目访问路径时通过server.context-path配置,
而在SpringBoot在2.0版本之后使用server.servlet.context-path配置项目访问路径。

第一点 后端接口能否访问
在这里我贴出了一段代码,包括application.yml配置文件,后续所有的演示都基于这段代码与配置文件。

package com.redisson.controller;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/redisson")
public class RedissonController 

    @Autowired
    RedissonClient redissonClient;

    @RequestMapping("/testRedissonClient")
    public void TestRedisson() 
        System.out.println("testRedissonClient: "+redissonClient);
    



我们开始调用一下接口,让404错误出现。(这里使用postman测试)
情况一:server.servlet.context-path(项目访问路径)漏写或者名称写错


情况二:类上面的@RequestMapping(“/demo”)注解里面的值漏写或者名称写错


情况三:方法上面的@RequestMapping(“/demo”)注解里面的值漏写或者名称写错


情况四:路径多写了一部分内容

总结:
端口号后面的访问路径书写错误,导致在访问后端接口时404问题的出现。像这种错误造成的直接后果就是请求无法进入到后端接口里。
.
解决方案:
出现404问题了,要认真排查访问接口的地址是否正确
一般请求访问的是:项目访问路径+类上面的@RequestMapping配置的value地址值+类上面的@RequestMapping配置的value地址值

第二点 后端接口的返回值是否能够映射到前端页面
对于接口访问路径书写正确,接口能访问成功的情况下仍然会出现404问题,具体操作案例如下。

package com.redisson.controller;

import com.redisson.bean.Person;
import com.redisson.utils.Msg;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/demo")
public class RedissonController 

    @Autowired
    RedissonClient redissonClient;

//    返回值是void,报404异常
    @RequestMapping("/testRedissonClient")
    public void TestRedisson() 
        System.out.println("testRedissonClient: "+redissonClient);
    

//返回值是null,报404异常
    @RequestMapping("/testRedissonClient2_1")
    public Msg TestRedisson2_1() 
        System.out.println("testRedissonClient2_1: "+redissonClient);
        return null;
    

//  返回值是空字符(比如 ""),报404异常
    @RequestMapping("/testRedissonClient2_2")
    public String TestRedisson2_2() 
        System.out.println("testRedissonClient2_2: "+redissonClient);
        return "";

    

//  返回值是任意字符串(比如 "success"),报404异常
    @RequestMapping("/testRedissonClient2")
    public String TestRedisson2() 
        System.out.println("testRedissonClient2: "+redissonClient);
        return "success";
    
//返回值是虽说是null,但是在@ResponseBody注解的加持下,则不会出现404异常问题
    @RequestMapping("/testRedissonClient3")
    @ResponseBody
    public Msg TestRedisson3() 
        System.out.println("testRedissonClient3: "+redissonClient);
        return null;
    

    //返回值是虽说是空字符,但是在@ResponseBody注解的加持下,则不会出现404异常问题
    @RequestMapping("/testRedissonClient4")
    @ResponseBody
    public String TestRedisson4() 
        System.out.println("testRedissonClient4: "+redissonClient);
        return "";
    
    //返回值是虽说是null,但是在@ResponseBody注解的加持下,则不会出现404异常问题
    @RequestMapping("/testRedissonClient5")
    @ResponseBody
    public String TestRedisson5() 
        System.out.println("testRedissonClient5: "+redissonClient);
        return null;
    

    //返回值是是一个json对象,但是在@ResponseBody注解的加持下,则不会出现404异常问题
    @RequestMapping("/testRedissonClient6")
    @ResponseBody
    public Msg TestRedisson6() 
        System.out.println("testRedissonClient6: "+redissonClient);
        return Msg.success("访问成功!").data("person",new Person());
    

    //返回值是是一个json对象,但是在没有@ResponseBody注解的加持下,则会出现404异常问题
    @RequestMapping("/testRedissonClient7")
    public Msg TestRedisson7() 
        System.out.println("testRedissonClient6: "+redissonClient);
        return Msg.success("访问成功!").data("person",new Person());
    

总结:
1、 添加了@ResponseBody注解的方法,在请求访问到方法里面后,返回到前端页面时是不会报404异常的。原因是@ResponseBody注解修饰的方法其返回值是不经过视图解析器解析的。
.

2、端口号后面的访问路径书写正确,请求能够进入到接口中,但是在返回到前端页面时报404异常。像这种错误造成的直接后果就是响应结果无法在页面展示。
.
分析:
之所以会出现这种问题是因为springBoot默认在没有@ResponseBody注解的加持下的情况下,返回的结果是经过视图解析器去解析并且匹配一个合适的前端页面,然后将结果展示出来的。当我们在项目中没有书写相应的前端页面时,自然视图解析器解析的结果无法匹配到,因此报404异常.
. .
解决方案:
出现404问题了,首先排查有没有添加@ResponseBody注解,其次要认真排查我们在项目中没有书写相应的前端页面。
(1) 在controller类的方法上面或者controller类上面添加@ResponseBody注解
(2) 方法的返回值要在项目中能够找到对应的前端页面。

TS爬虫,爬取博客园demo,全网最详细!

  

/**
 * 返回脚本节点的数据结构。
 * 可以直接返回DbTableInfo类型的数据,ddl存储查询的sql,table存储的是对应的物理表名。也可以返回一个二维数组。
 * 使用场景:
 * 1. 调用api处理gis数据更新,并需要将处理后的物理表输出为模型。
 * 2. 调用api查询数据,读取仪表板或报表的查询条件作为参数,并将实时查询结果返回。
 */
function onProcessData(context: IDataFlowScriptNodeContext): DbTableInfo | any[][] 
    const Jsoup = Java.type("org.jsoup.Jsoup");
    const url = "https://www.cnblogs.com/";
    let data = [];
    for (let i = 1; i <= 3; i++) 
        let res: string = post(
            url: "https://www.cnblogs.com/AggSite/AggSitePostList",
            data: 
                "CategoryType": "SiteHome",
                "ParentCategoryId": 0,
                "CategoryId": 808,
                "PageIndex": i.toFixed(),
                "TotalPostCount": 4000,
                "ItemListActionName": "AggSitePostList"
            ,
            headers: 
                "Content-Type": "application/json"
            
        ).responseText;
        let document = Jsoup.parse(res);

        let elements = document.getElementsByClass("post-item");

        for (let element of elements) 
            let row = [];

            let titleElement = element.getElementsByClass("post-item-title");
            let summaryElement = element.getElementsByClass("post-item-summary");
            let authorElement = element.select(".post-item-foot > .post-item-author");
            //let authorElement = element.select("section > footer > a.:nth-child(1)")
            let createDateElement = element.select("section > footer > span.post-meta-item > span");
            let commentCountElement = element.select("section > footer > a:nth-child(4) > span");
            let viewCountElement = element.select("section > footer > a:nth-child(5) > span");


            // 博客 ID
            let id = element.attr("data-post-id");
            // 博客标题
            let title = titleElement.text();
            // 内容简介
            let summary = summaryElement.get(0).ownText();
            let authorUrl = authorElement.select("a").get(0).attr("href");
            // 作者 ID
            let authorId = authorUrl.substring(url.length, authorUrl.length() - 1);
            // 作者网名
            let authorName = authorElement.select("span").get(0).text();
            // 创建时间
            let createDate = createDateElement.text();
            // 点赞数
            let diggCount = element.getElementById("digg_count_" + id).text();
            // 评论数
            let commentCount = commentCountElement.text();
            // 浏览量
            let viewCount = viewCountElement.text();
            print("---------------------------------------------")
            row.push(id);
            row.push(title);
            row.push(summary);
            row.push(authorUrl);
            row.push(authorId);
            row.push(authorName);
            row.push(createDate);
            row.push(diggCount);
            row.push(commentCount);
            row.push(viewCount);

            print("row======" + row);
            data.push(row);

        

    

    return data;
 
 
========================================================================通过调用api获取cnode数据


/**
 * 返回脚本节点字段结构。
 * 使用场景:
 * 1. 通过脚本爬取数据到数据仓库,需要生成定义好的字段结构。
 * 2. 通过脚本解析json数据,需要预解析几行数据生成字段。
 */
function onProcessFields(context: IDataFlowScriptNodeContext): DbFieldInfo[] 
    return [
         name: "id", length: 150, dataType: FieldDataType.C ,
         name: "title", length: 200, dataType: FieldDataType.C ,
         name: "summary", length: 200, dataType: FieldDataType.C ,
         name: "authorUrl", length: 200, dataType: FieldDataType.C ,
         name: "authorId", length: 20, dataType: FieldDataType.C ,
         name: "authorName", length: 200, dataType: FieldDataType.C ,
         name: "createDate", length: 100, dataType: FieldDataType.C ,
         name: "diggCount", length: 20, dataType: FieldDataType.C ,
         name: "commentCount", length: 20, dataType: FieldDataType.C ,
         name: "viewCount", length: 20, dataType: FieldDataType.C 
    ];


/**
 * 返回脚本节点的数据结构。
 * 可以直接返回DbTableInfo类型的数据,ddl存储查询的sql,table存储的是对应的物理表名。也可以返回一个二维数组。
 * 使用场景:
 * 1. 调用api处理gis数据更新,并需要将处理后的物理表输出为模型。
 * 2. 调用api查询数据,读取仪表板或报表的查询条件作为参数,并将实时查询结果返回。
 */
function onProcessData(context: IDataFlowScriptNodeContext): DbTableInfo | any[][] 
    const Jsoup = Java.type("org.jsoup.Jsoup");
    const url = "https://www.cnblogs.com/";
    let data = [];
    for (let i = 1; i <= 3; i++) 
        let res: string = post(
            url: "https://www.cnblogs.com/AggSite/AggSitePostList",
            data: 
                "CategoryType": "SiteHome",
                "ParentCategoryId": 0,
                "CategoryId": 808,
                "PageIndex": i.toFixed(),
                "TotalPostCount": 4000,
                "ItemListActionName": "AggSitePostList"
            ,
            headers: 
                "Content-Type": "application/json"
            
        ).responseText;
        let document = Jsoup.parse(res);

        let elements = document.getElementsByClass("post-item");

        for (let element of elements) 
            let row = [];

            let titleElement = element.getElementsByClass("post-item-title");
            let summaryElement = element.getElementsByClass("post-item-summary");
            let authorElement = element.select(".post-item-foot > .post-item-author");
            //let authorElement = element.select("section > footer > a.:nth-child(1)")
            let createDateElement = element.select("section > footer > span.post-meta-item > span");
            let commentCountElement = element.select("section > footer > a:nth-child(4) > span");
            let viewCountElement = element.select("section > footer > a:nth-child(5) > span");


            // 博客 ID
            let id = element.attr("data-post-id");
            // 博客标题
            let title = titleElement.text();
            // 内容简介
            let summary = summaryElement.get(0).ownText();
            let authorUrl = authorElement.select("a").get(0).attr("href");
            // 作者 ID
            let authorId = authorUrl.substring(url.length, authorUrl.length() - 1);
            // 作者网名
            let authorName = authorElement.select("span").get(0).text();
            // 创建时间
            let createDate = createDateElement.text();
            // 点赞数
            let diggCount = element.getElementById("digg_count_" + id).text();
            // 评论数
            let commentCount = commentCountElement.text();
            // 浏览量
            let viewCount = viewCountElement.text();
            print("---------------------------------------------")
            row.push(id);
            row.push(title);
            row.push(summary);
            row.push(authorUrl);
            row.push(authorId);
            row.push(authorName);
            row.push(createDate);
            row.push(diggCount);
            row.push(commentCount);
            row.push(viewCount);

            print("row======" + row);
            data.push(row);

        

    

    return data;
 
 
 
 
 

以上是关于关于访问后端接口报404的问题——全网最详细的404错误详解的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#nginx代理后端接口404

❄️全网最详细的Python入门基础教程,Python最全教程(非常详细,整理而来)

❄️全网最详细的Python入门基础教程,Python最全教程(非常详细,整理而来)

Promise使用时应注意的问题

vue跨域请求时报403

小程序 webview 部分用户打开后白屏