无法在从 Maven SpringBoot 后端发送的 React 中获取 JSON 对象

问题描述

我正在使用 Maven SpringBoot 后端在 React 中构建应用程序的前端。后端控制器从 Plaid API 调用获取数据并将其组装成一个 JSONObject,包含一个对象和一个数组。我可以在后端看到该对象正确填充了数据。

在前端,我使用 fetch() 请求来启动 API 调用,然后想将对象解析为 JSON 以便我可以使用它。 API 调用返回 200 状态,但返回的 JSON 对象为空。我不确定在后端和前端之间传递对象之间会丢失什么。

后端代码(返回的“loanResp”对象是我想要获取的对象):

package com.alumsum.backend.controllers;

import com.alumsum.backend.api.PlaidApiCaller;
import com.alumsum.backend.cache.UserLoanCache;
import com.alumsum.backend.model.FinUser;
import com.alumsum.backend.model.FinUserRepository;
import com.alumsum.backend.model.LoanAggregation;
import com.alumsum.backend.model.LoanAggregationRepository;
import com.alumsum.backend.model.PlaidFinancialInfo;
import com.alumsum.backend.model.PlaidFinancialInfoRepository;
import com.alumsum.backend.model.RegUser;
import com.alumsum.backend.model.RegUserRepository;
import com.alumsum.backend.utilities.Loancalculator;
import com.alumsum.backend.utilities.UserHandlingUtilities;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.plaid.client.request.ItempublicTokenExchangeRequest;
import com.plaid.client.response.ItempublicTokenExchangeResponse;
import com.plaid.client.response.LiabilitiesGetResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import retrofit2.Response;

import javax.validation.Valid;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Controller for Plaid API interactions.
 */
@Slf4j
@RestController
@RequestMapping("/plaid_api")
public class PlaidController implements PlaidApiCaller {

    @Autowired
    private RegUserRepository regUserRepository;
    @Autowired
    private PlaidFinancialInfoRepository plaidFinancialInfoRepository;
    @Autowired
    private UserLoanCache userLoanCache;
    @Autowired
    private LoanAggregationRepository aggregationRepository;
    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;
    @Autowired
    private FinUserRepository repository;


    @GetMapping("/plaid/plaid_fin_info")
    ResponseEntity<?> getPlaidUserInfo(@AuthenticationPrincipal OAuth2User principal) throws IOException {
        final JsonObject loanResp = new JsonObject();
        final JsonArray individualLoans =new JsonArray();
        final String userId = findUserIdFromAuthentication(principal);
        final RegUser user = regUserRepository.findRegUserById(userId);
        final String userName = user.getUserName();
        final List<PlaidFinancialInfo> group = plaidFinancialInfoRepository.findplaidFinancialInfoByUserName(userName);
        for (PlaidFinancialInfo finInfo : group) {
            final String accesstoken = finInfo.getAccesstoken();
            LiabilitiesGetResponse.Liabilities liabilities = getLiabilitiesInfo(accesstoken);
            List<LiabilitiesGetResponse.StudentLoanLiability> loans = liabilities.getStudent();
            //Account id in the cache
            for (LiabilitiesGetResponse.StudentLoanLiability loan : loans) {
                userLoanCache.add(loan.getAccountId(),loan,50000L);
                final JsonObject singleLoan =new JsonObject();
                singleLoan.addProperty("account_id",loan.getAccountId());
                singleLoan.addProperty("account_number",loan.getAccountNumber());
                singleLoan.addProperty("loan_name",loan.getLoanName());
                singleLoan.addProperty("loan_status",loan.getLoanStatus().getType());
                singleLoan.addProperty("is_overdue",loan.getIsOverdue());
                singleLoan.addProperty("expected_payoff_date",loan.getExpectedPayoffDate());
                singleLoan.addProperty("interest_rate",loan.getInterestRatePercentage());
                singleLoan.addProperty("principal",loan.getoriginationPrincipalAmount());
                singleLoan.addProperty("outstanding_interest",loan.getoutstandingInterestAmount());
                singleLoan.addProperty("loan_left",loan.getoriginationPrincipalAmount() + loan.getoutstandingInterestAmount());
                singleLoan.addProperty("minimum_payment",loan.getMinimumPaymentAmount());
                singleLoan.addProperty("last_payment",loan.getLastPaymentAmount());
                singleLoan.addProperty("origination_date",loan.getoriginationDate());
                singleLoan.addProperty("payments_made",loan.getPslfStatus().getPaymentsMade());
                singleLoan.addProperty("payments_left",loan.getPslfStatus().getPaymentsRemaining());
                individualLoans.add(singleLoan);
            }
        }
        loanResp.add("student_loan_info",individualLoans);
        final JsonObject loanAggregate = Loancalculator.aggregateLoans(loanResp);
        final Double totalDebt = loanAggregate.get("total_loan_debt").getAsDouble();
        final Double totalInterest = loanAggregate.get("average_interest_rate").getAsDouble();
        final String oktaId = UserHandlingUtilities.findOktaUserId(principal);
        final LoanAggregation loanAgggregation= new LoanAggregation(userName,totalDebt,totalInterest,oktaId);
        createOrUpdateLoanAggregation(loanAgggregation);
        loanResp.add("loan_aggregate",loanAggregate);

        return ResponseEntity.ok().body(loanResp);
    }

    private void createOrUpdateLoanAggregation(LoanAggregation loanAgggregation) {
        final String oktaId = loanAgggregation.getoktaId();
        final Optional<LoanAggregation> loanInfo = Optional.ofNullable(aggregationRepository.findLoanAggregationByOktaId(oktaId));
        final FinUser finUser = repository.findAllByRegUserId(oktaId).get(0);
        // if we find user,we PUT
        if(!loanInfo.isPresent()){
            createLoanAggregation(loanAgggregation);
            finUser.setLoanAggregations(loanAgggregation);
            repository.save(finUser);
        }
        else{
            final LoanAggregation updatedAggregation = loanInfo.get();
            updatedAggregation.setInterestRate(loanAgggregation.getInterestRate());
            updatedAggregation.setTotalDebt(loanAgggregation.getTotalDebt());
            updateLoanAggregation(updatedAggregation);
        }
    }

前端代码

import React,{Component} from 'react';
import { withCookies,Cookies } from 'react-cookie';
import { instanceOf } from 'prop-types';
import './QuickStats.scss';

class QuickStats extends Component {
    static propTypes = {
        cookies: instanceOf(Cookies).isrequired
    };

    constructor(props) {
        super(props);
        const {cookies} = props;
        this.state = {
            item: {},user: this.props.data,csrftoken: cookies.get('XSRF-TOKEN')
        };
    }

    async componentDidMount() {
        const {item,csrftoken} = this.state;
        const requestOptions = {
            method: 'GET',headers: { 
                'X-XSRF-TOKEN': csrftoken,'Accept': 'application/json','Content-Type': 'application/json'
            },credentials: 'include'
        };
        await fetch('/plaid_api/plaid/plaid_fin_info',requestOptions)
            .then(async response => {
                console.log(response);
                const data = await response.json();
                console.log("RESPONSE RECEIVED(3): ",data);
                // check for error response
                if (!response.ok) {
                    // get error message from body or default to response status
                    const error = (data && data.message) || response.status;
                    return Promise.reject(error);
                }
            })
            .then(data => {
                this.setState({item: data})
            })
            .catch((err) => {
                console.log("ERROR: ",err);
            });
    }

    render(){
        const {item} = this.state;
        return (
            <div className="quick-stats">
                <div>
                    <div className="container-heading text-left">Quick Stats</div>
                    <div className="display-flex mr-t5 flex-wrap">
                        <div style={{ backgroundColor: '#393e46',color: '#ffffff' }} className="tile flex-1 pd-20 text-center">
                            <div className="text-right mr-b5">
                                <img src={process.env.PUBLIC_URL + '/svg/information.svg'} alt="info" />
                            </div>
                            <div className="heading"></div>
                            <div className="sub-heading mr-t5">Principal remaining.</div>
                        </div>
                        <div style={{ backgroundColor: '#C9CAC8',color: '#4C4D4F' }} className="tile flex-1 pd-20 text-center">
                            <div className="text-right mr-b5">
                                <img src={process.env.PUBLIC_URL + '/svg/information.svg'} alt="info" />
                            </div>
                            <div className="heading"></div>
                            <div className="sub-heading mr-t5">You'll be debt-free march 2038.</div>
                        </div>
                        <div style={{ backgroundColor: '#288B6A',color: '#ffffff' }} className="tile flex-1 pd-20 text-center">
                            <div className="text-right mr-b5">
                                <img src={process.env.PUBLIC_URL + '/svg/information.svg'} alt="info" />
                            </div>
                            <div className="heading">%</div>
                            <div className="sub-heading mr-t5">Average interest rate of your loans.</div>
                        </div>
                    </div>
                </div>
            </div>
        )
    };
}

export default withCookies(QuickStats);

响应请求:

Request URL: http://localhost:3000/plaid_api/plaid/plaid_fin_info
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:3000
Referrer Policy: strict-origin-when-cross-origin
cache-control: no-cache,no-store,max-age=0,must-revalidate
connection: close
content-length: 2
content-type: application/json
expires: 0
pragma: no-cache
vary: Accept-Encoding
x-content-type-options: nosniff
x-frame-options: DENY
X-Powered-By: Express
x-xss-protection: 1; mode=block
Accept: application/json
Accept-Encoding: gzip,deflate,br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Type: application/json
Host: localhost:3000
Referer: http://localhost:3000/alumsum/dashboard
Sec-Fetch-Dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/88.0.4324.192 Safari/537.36
Response: {}

谁能确定我做错了什么,为什么响应返回空白而不是正确的数据?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)