
本教程详细介绍了如何将react.js前端与php后端通过restful api进行连接。文章将涵盖后端api的构建、前端数据请求与处理,以及跨域资源共享(cors)等关键配置,旨在帮助开发者高效地构建全栈web应用。
在现代Web开发中,前端与后端分离已成为主流实践。React.js作为流行的前端库,负责构建用户界面;而PHP则常用于处理服务器端逻辑、数据库交互和API服务。通过RESTful API,两者可以无缝协作,共同构建功能强大的Web应用程序。
React.js应用通常运行在用户的浏览器中,负责渲染UI和响应用户操作。它通过HTTP请求(如GET、POST、PUT、DELETE)与后端API进行通信,获取或提交数据。PHP后端则接收这些请求,处理业务逻辑,与数据库交互,并以JSON等格式返回数据给前端。这种模式的核心是RESTful API,它定义了一套标准化的接口,使得不同技术栈的组件能够互相理解和通信。
为了将原始的PHP CLI脚本转换为可供React.js调用的Web API,我们需要进行以下改造:
假设我们有一个data.json文件作为数据源:
立即学习“PHP免费学习笔记(深入)”;
[
{ "offerId": 1, "productTitle": "Laptop", "vendorId": 101, "price": 1200 },
{ "offerId": 2, "productTitle": "Mouse", "vendorId": 101, "price": 25 },
{ "offerId": 3, "productTitle": "Keyboard", "vendorId": 102, "price": 75 },
{ "offerId": 4, "productTitle": "Monitor", "vendorId": 103, "price": 300 },
{ "offerId": 5, "productTitle": "Webcam", "vendorId": 102, "price": 50 },
{ "offerId": 6, "productTitle": "Headphones", "vendorId": 101, "price": 150 }
]我们将原有的PHP代码封装为一个API入口文件 api.php:
<?php
// 设置CORS头,允许React开发服务器访问
header("Access-Control-Allow-Origin: http://localhost:3000"); // 替换为你的React应用地址
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// 处理OPTIONS请求,用于CORS预检
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
/**
* The interface provides the contract for different readers
* E.g. it can be XML/JSON Remote Endpoint, or CSV/JSON/XML local files
*/
interface ReaderInterface
{
/**
* Read in incoming data and parse to objects
*/
public function read(string $input): OfferCollectionInterface;
}
/**
* Interface of Data Transfer Object, that represents external JSON data
*/
interface OfferInterface
{
}
/**
* Interface for The Collection class that contains Offers
*/
interface OfferCollectionInterface
{
public function get(int $index): OfferInterface;
public function getIterator(): Iterator;
}
/* *********************************** */
class Offer implements OfferInterface
{
public $offerId;
public $productTitle;
public $vendorId;
public $price;
public function __toString(): string
{
return "$this->offerId | $this->productTitle | $this->vendorId | $this->price\n";
}
}
class OfferCollection implements OfferCollectionInterface
{
private $offersList = array();
public function __construct($data)
{
if (is_array($data)) {
foreach ($data as $json_object) {
$offer = new Offer();
$offer->offerId = $json_object->offerId;
$offer->productTitle = $json_object->productTitle;
$offer->vendorId = $json_object->vendorId;
$offer->price = $json_object->price;
array_push($this->offersList, $offer);
}
}
}
public function get(int $index): OfferInterface
{
return $this->offersList[$index];
}
public function getIterator(): Iterator
{
return new ArrayIterator($this->offersList);
}
public function __toString(): string
{
return implode("\n", $this->offersList);
}
// 新增方法:将OfferCollection转换为数组,以便json_encode
public function toArray(): array
{
$result = [];
foreach ($this->offersList as $offer) {
$result[] = [
'offerId' => $offer->offerId,
'productTitle' => $offer->productTitle,
'vendorId' => $offer->vendorId,
'price' => $offer->price,
];
}
return $result;
}
}
class Reader implements ReaderInterface
{
/**
* Read in incoming data and parse to objects
*/
public function read(string $input): OfferCollectionInterface
{
if ($input != null) {
$content = file_get_contents($input);
$json = json_decode($content);
$result = new OfferCollection($json);
return $result;
}
return new OfferCollection(null);
}
}
class Logger
{
private $filename = "logs.txt";
public function info($message): void
{
$this->log($message, "INFO");
}
public function error($message): void
{
$this->log($message, "ERROR");
}
private function log($message, $type): void
{
$myfile = fopen($this->filename, "a") or die("Unable to open file!");
$txt = "[$type] $message\n";
fwrite($myfile, $txt);
fclose($myfile);
}
}
$json_url = 'data.json';
$json_reader = new Reader();
$offers_list = $json_reader->read($json_url);
function count_by_price_range($price_from, $price_to)
{
global $offers_list;
$count = 0;
foreach ($offers_list->getIterator() as $offer) {
if ($offer->price >= $price_from && $offer->price <= $price_to) {
$count++;
}
}
return $count;
}
function count_by_vendor_id($vendorId)
{
global $offers_list;
$count = 0;
foreach ($offers_list->getIterator() as $offer) {
if ($offer->vendorId == $vendorId) {
$count++;
}
}
return $count;
}
// 获取请求路径和参数
$request_uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path_segments = explode('/', trim($request_uri, '/'));
$api_endpoint = end($path_segments); // 假设API路径的最后一段是功能名称
$logger = new Logger();
$response_data = [];
$status_code = 200;
switch ($api_endpoint) {
case "count_by_price_range": {
$price_from = $_GET['from'] ?? null;
$price_to = $_GET['to'] ?? null;
if ($price_from !== null && $price_to !== null) {
$logger->info("Getting Count By Price Range From: $price_from TO $price_to");
$response_data = ['count' => count_by_price_range((float)$price_from, (float)$price_to)];
} else {
$status_code = 400;
$response_data = ['error' => 'Missing price range parameters (from, to).'];
}
break;
}
case "count_by_vendor_id": {
$vendorId = $_GET['vendorId'] ?? null;
if ($vendorId !== null) {
$logger->info("Getting Count By vendor Id: $vendorId");
$response_data = ['count' => count_by_vendor_id((int)$vendorId)];
} else {
$status_code = 400;
$response_data = ['error' => 'Missing vendorId parameter.'];
}
break;
}
case "offers": { // 新增一个获取所有offer的接口
$response_data = ['offers' => $offers_list->toArray()];
break;
}
default: {
$status_code = 404;
$response_data = ['error' => 'API endpoint not found.'];
break;
}
}
http_response_code($status_code);
echo json_encode($response_data);
?>将 api.php 和 data.json 放在一个支持PHP的Web服务器(如Apache或Nginx)的根目录下。 现在,你可以通过访问类似 http://localhost/api.php/count_by_price_range?from=50&to=200 或 http://localhost/api.php/offers 来测试API。
接下来,我们创建一个简单的React组件来调用这个PHP API并显示数据。
初始化React项目 如果你还没有React项目,可以使用Create React App快速搭建:
npx create-react-app react-php-app cd react-php-app npm start
编写React组件 修改 src/App.js 文件,添加一个组件来获取并展示数据:
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [offers, setOffers] = useState([]);
const [priceRangeCount, setPriceRangeCount] = useState(0);
const [vendorIdCount, setVendorIdCount] = useState(0);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
// PHP API 的基础URL,请根据你的实际部署修改
const API_BASE_URL = 'http://localhost/api.php';
useEffect(() => {
const fetchData = async () => {
try {
// 获取所有Offers
const offersResponse = await fetch(`${API_BASE_URL}/offers`);
if (!offersResponse.ok) {
throw new Error(`HTTP error! status: ${offersResponse.status}`);
}
const offersData = await offersResponse.json();
setOffers(offersData.offers || []);
// 获取价格区间统计
const priceRangeResponse = await fetch(`${API_BASE_URL}/count_by_price_range?from=50&to=200`);
if (!priceRangeResponse.ok) {
throw new Error(`HTTP error! status: ${priceRangeResponse.status}`);
}
const priceRangeData = await priceRangeResponse.json();
setPriceRangeCount(priceRangeData.count || 0);
// 获取供应商ID统计
const vendorIdResponse = await fetch(`${API_BASE_URL}/count_by_vendor_id?vendorId=101`);
if (!vendorIdResponse.ok) {
throw new Error(`HTTP error! status: ${vendorIdResponse.status}`);
}
const vendorIdData = await vendorIdResponse.json();
setVendorIdCount(vendorIdData.count || 0);
} catch (error) {
console.error("Error fetching data:", error);
setError(error);
} finally {
setLoading(false);
}
};
fetchData();
}, []); // 空数组表示只在组件挂载时运行一次
if (loading) return <div>Loading data...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div className="App">
<h1>React.js & PHP API 集成示例</h1>
<h2>所有商品列表</h2>
{offers.length > 0 ? (
<ul>
{offers.map(offer => (
<li key={offer.offerId}>
ID: {offer.offerId}, Title: {offer.productTitle}, Vendor: {offer.vendorId}, Price: ${offer.price}
</li>
))}
</ul>
) : (
<p>没有商品数据。</p>
)}
<h2>统计信息</h2>
<p>价格在 $50 到 $200 之间的商品数量: {priceRangeCount}</p>
<p>供应商ID为 101 的商品数量: {vendorIdCount}</p>
</div>
);
}
export default App;在开发阶段,React应用通常运行在 http://localhost:3000,而PHP后端可能运行在 http://localhost 或 http://localhost:80。由于它们端口或域名不同,浏览器会阻止React应用直接访问PHP API,这就是所谓的“跨域”问题。
为了解决这个问题,PHP后端需要发送特定的HTTP响应头,告知浏览器允许来自React应用源的请求。在 api.php 的开头,我们已经添加了以下CORS头:
header("Access-Control-Allow-Origin: http://localhost:3000"); // 允许来自React开发服务器的请求
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // 允许的HTTP方法
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
// 处理OPTIONS请求,用于CORS预检
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}通过RESTful API,React.js和PHP可以高效地协同工作,分别专注于前端的用户体验和后端的业务逻辑。构建一个稳健的API涉及请求处理、数据格式化、CORS配置以及安全性考量。遵循本教程的指导,开发者可以顺利地将React.js前端与PHP后端集成,构建出功能完善、结构清晰的Web应用程序。
以上就是React.js与PHP后端集成:构建RESTful API应用教程的详细内容,更多请关注php中文网其它相关文章!
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号