问题描述
我正在使用 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 (将#修改为@)