核心思路
跨服务器提交的核心思想是:在A网站(源服务器)上,不直接处理表单数据,而是将数据打包发送到B网站(目标服务器)的一个专门接口,B网站接收到数据后,再进行正常的入库或其他操作。
由于浏览器的同源策略,直接使用AJAX请求另一个域名的接口可能会被阻止,我们需要一些技术手段来绕过或解决这个问题。
使用服务器端代理(推荐,最安全可靠)
这种方法的原理是:用户在A网站提交表单,请求先发送到A网站自己的一个处理页面(如 post.php),这个页面使用PHP的cURL库,在服务器端向B网站的目标接口发起请求,因为这是服务器与服务器之间的通信,完全不受浏览器同源策略的限制。
优点:
- 安全性高:目标服务器的接口地址和密钥永远不会暴露在前端代码中。
- 兼容性好:不依赖浏览器的特定功能,所有浏览器都能正常工作。
- 稳定可靠:cURL功能强大,可以处理各种复杂的请求。
缺点:
- 需要在A网站的服务器上开启并配置cURL扩展(99%的虚拟主机或云服务器都默认支持)。
实现步骤:
第1步:在B网站(目标服务器)创建接收接口
- 在B网站根目录下创建一个新文件,
receive.php。 - 这个文件将负责接收来自A网站的数据,并进行处理(如入库)。
receive.php (B网站) 代码示例:
<?php
// 设置响应头,告诉A网站服务器这是一个JSON响应
header('Content-Type: application/json; charset=utf-8');
// 1. 安全验证(非常重要!)
// 这里使用一个预定义的Token,A网站提交时需要带上这个Token
$secretToken = 'YOUR_SECRET_TOKEN_HERE'; // 请务必设置一个复杂的、不易猜测的Token
if (empty($_POST['token']) || $_POST['token'] !== $secretToken) {
http_response_code(403); // 返回禁止访问状态码
echo json_encode(['status' => 'error', 'message' => 'Invalid token.']);
exit;
}
// 2. 接收并处理数据
// 从POST请求中获取表单数据
$title = isset($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : '';
$content = isset($_POST['content']) ? htmlspecialchars(trim($_POST['content'])) : '';
$email = isset($_POST['email']) ? htmlspecialchars(trim($_POST['email'])) : '';
// 这里是你原有的入库逻辑,例如插入到dede_addonarticle表
// 注意:你需要根据B网站的数据库结构和织梦的API进行调整
// require_once(DEDEINC.'/datalistcp.class.php');
// require_once(DEDEINC.'/custom.func.php'); // 可能需要引入一些函数
// 示例:直接入库(请根据实际情况修改)
if (!empty($title) && !empty($content)) {
// 连接B网站的数据库
// $dbhost = 'localhost';
// $dbuser = 'b_db_user';
// $dbpass = 'b_db_password';
// $dbname = 'b_database_name';
// $link = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);
// if (!$link) { die('Error connecting to database'); }
// $sql = "INSERT INTO dede_addonarticle (title, body, typeid, pubdate) VALUES ('$title', '$content', 1, ".time().")";
// mysqli_query($link, $sql);
// mysqli_close($link);
// 为了演示,我们只返回成功信息
echo json_encode([
'status' => 'success',
'message' => 'Data received and saved successfully!',
'data' => [
'title' => $title,
'content' => $content,
'email' => $email
]
]);
} else {
echo json_encode(['status' => 'error', 'message' => 'Title and content are required.']);
}
?>
第2步:在A网站(源服务器)创建代理提交页面
- 在A网站根目录下创建一个新文件,
proxy.php。 - 这个文件接收A网站前端发来的数据,并使用cURL转发给B网站的
receive.php。
proxy.php (A网站) 代码示例:
<?php
// 设置响应头
header('Content-Type: application/json; charset=utf-8');
// 1. 接收前端传来的数据(可以是POST或GET)
$data = [ => isset($_POST['title']) ? trim($_POST['title']) : '',
'content' => isset($_POST['content']) ? trim($_POST['content']) : '',
'email' => isset($_POST['email']) ? trim($_POST['email']) : '',
'token' => 'YOUR_SECRET_TOKEN_HERE' // 必须和B网站receive.php中的Token一致
];
// 2. 使用cURL向B网站发送请求
$ch = curl_init();
// B网站接收接口的完整URL
$url = 'http://www.b.com/receive.php'; // 请替换为B网站的实际域名
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true); // 使用POST方法
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); // 将数据转换为URL编码的字符串
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将curl_exec()获取的信息以字符串返回,而不是直接输出
curl_setopt($ch, CURLOPT_TIMEOUT, 15); // 设置超时时间,防止长时间等待
// 在开发环境下,可以忽略SSL证书验证(生产环境请谨慎)
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// 执行请求
$response = curl_exec($ch);
// 检查是否有错误发生
if (curl_errno($ch)) {
echo json_encode(['status' => 'error', 'message' => 'cURL request failed: ' . curl_error($ch)]);
} else {
// 将B网站返回的响应直接返回给前端
echo $response;
}
curl_close($ch);
?>
第3步:修改A网站的织梦表单模板
找到你的织梦表单模板文件(通常是 plus/diyform.htm),修改其中的JavaScript代码,让它提交数据到本地的 proxy.php,而不是默认的 /plus/diy.php。
diyform.htm (A网站模板) 示例:
<form name="myform" action="/proxy.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="diyid" value="{dede:global.diyid/}" />
<input type="hidden" name="do" value="2" />
<p>标题:<input type="text" name="title" id="title" class="intxt" style="width:250px" /></p>
<p>内容:<textarea name="content" id="content" style="width:360px;height:150px"></textarea></p>
<p>邮箱:<input type="text" name="email" id="email" class="intxt" style="width:250px" /></p>
<p>
<input type="submit" name="submit" value="提 交" class="btn" />
</p>
</form>
<script>
document.querySelector('form').addEventListener('submit', function(e) {
// 这里可以添加前端的简单验证
const title = document.getElementById('title').value;
if (!title) {
alert('标题不能为空!');
e.preventDefault(); // 阻止表单提交
return;
}
// 表单会正常提交到 /proxy.php,无需复杂的AJAX代码
// proxy.php会处理cURL请求并返回结果
});
</script>
使用JSONP(仅适用于GET请求,已不推荐)
JSONP(JSON with Padding)是一种早期用于解决跨域请求的技巧,它利用了<script>标签的src属性不受同源策略限制的特性。
重要提示:JSONP只支持GET请求,不安全(容易受到XSS攻击),且在现代Web开发中已基本被CORS取代。仅当你无法修改服务器端代码(B网站无法提供接口)且数据量不大、不敏感时,才考虑此方案。**
实现步骤:
第1步:B网站(目标服务器)支持JSONP
B网站的接收页面 receive_jsonp.php 必须能返回JSONP格式的数据。
receive_jsonp.php (B网站) 代码示例:
<?php
// 接收回调函数名,前端会传过来
$callback = isset($_GET['callback']) ? $_GET['callback'] : 'callback';
// 你的业务逻辑处理
$data = ['status' => 'success', 'message' => 'Data received via JSONP'];
// 返回JSONP格式
echo $callback . '(' . json_encode($data) . ')';
?>
第2步:A网站(源服务器)前端使用JSONP
在A网站的织梦表单模板中,使用JavaScript动态创建<script>标签来发起请求。
diyform.htm (A网站模板) 示例:
<form name="myform" action="#" onsubmit="return false;" method="post">
<!-- 表单字段同上 -->
<p>标题:<input type="text" name="title" id="title" class="intxt" style="width:250px" /></p>
<p>邮箱:<input type="text" name="email" id="email" class="intxt" style="width:250px" /></p>
<p><input type="button" name="submit" value="提 交" class="btn" onclick="submitForm()" /></p>
</form>
<script>
function submitForm() {
const title = document.getElementById('title').value;
const email = document.getElementById('email').value;
// 动态创建script标签
const script = document.createElement('script');
// B网站接口,并带上回调函数名和参数
// 注意:参数需要通过URL传递,不适合大量数据
script.src = 'http://www.b.com/receive_jsonp.php?callback=handleResponse&title=' + encodeURIComponent(title) + '&email=' + encodeURIComponent(email);
// 将script标签添加到body中,请求会自动发送
document.body.appendChild(script);
}
// 这个函数名必须和B网站请求URL中的callback参数值一致
function handleResponse(data) {
console.log(data); // 在控制台打印B网站返回的数据
if (data.status === 'success') {
alert('提交成功!');
// 可以在这里清空表单或做其他操作
} else {
alert('提交失败:' + data.message);
}
// 请求完成后,移除这个script标签,避免重复加载
document.body.removeChild(document.querySelector('script[src^="http://www.b.com/receive_jsonp.php"]'));
}
</script>
总结与建议
| 特性 | 服务器端代理 | JSONP |
|---|---|---|
| 安全性 | 高(密钥不暴露) | 低(参数暴露,易受攻击) |
| 请求方式 | 支持POST和GET | 仅支持GET |
| 数据量 | 无限制(受服务器配置影响) | 受URL长度限制 |
| 兼容性 | 好(依赖服务器cURL) | 好(依赖浏览器<script>
|
| 推荐度 | ★★★★★ (强烈推荐) | ★☆☆☆☆ (仅作为备选) |
对于织梦CMS的表单跨服务器提交,强烈建议你使用方案一(服务器端代理),它更安全、更强大,是处理此类问题的标准做法,方案二可以作为在特定极端情况下的备选方案。
