geekality/php-cross-domain-proxy

简单的自包含PHP代理,用于跨域AJAX请求。

v2.2.0 2023-09-15 09:05 UTC

This package is auto-updated.

Last update: 2024-09-15 11:11:17 UTC


README

Latest version Downloads License

客户端HTTP请求受浏览器跨域限制。

最好通过在您尝试调用的服务器上启用 CORS(http://enable-cors.org/server.html)来解决,但有时因为某些原因这可能并不可能。

一个简单的解决方案是在与您的客户端脚本相同的域上有一个服务器端代理脚本(例如,两者都在 api.example.com),然后让服务器代表客户端执行这些跨域请求。

这就是这样一个脚本。

安装

由于 proxy.php 完全自包含,您可以简单地将

  1. proxy.php 复制到您的 Web 应用程序中
  2. 定义 $whitelist 数组
  3. 基本上就是这些...

如果您使用 Composer,您也可以像这样将 geekality/php-cross-domain-proxy 添加到您的 composer.json

"require":
{
	"geekality/php-cross-domain-proxy": "1.*"
},

然后例如将以下 proxy.php 添加到您的 Web 应用程序中

<?php
	require 'vendor/autoload.php';

	Geekality\CrossOriginProxy::proxy([
		['host' => 'example.com'],
	]);

用法

在客户端,当执行跨域请求时

  1. url 指向 proxy.php 脚本。
  2. 设置HTTP头 X-Proxy-URL 为您要调用的任何URL,例如 http://api.example.com/some/path

所有参数和HTTP头(除 CookieHost 外)都将用于重新创建请求,并由代理在服务器端执行。完成后,它将镜像响应,包括头信息,并将它们以尽可能接近直接调用的方式返回给客户端脚本。

使用jQuery的用法

基本的GET请求

$.ajax({
	url: 'proxy.php',
	cache: false,
	headers: {
		'X-Proxy-URL': 'http://example.com/api/method',
	},
})

通过全局 ajaxSend 事件自动处理

$(function()
{
	// Hook up the event handler
	$(document).ajaxSend(useCrossDomainProxy);
});

function useCrossDomainProxy(event, jqxhr, options)
{
	if(options.crossDomain)
	{
		// Copy URL to HTTP header
		jqxhr.setRequestHeader('X-Proxy-URL', options.url);

		// Set URL to the proxy
		options.url = 'proxy.php';

		// Since all cross-origin URLs will now look the same to the browser,
		// you can add a timestamp, which will prevent browser caching.
		options.url += '?_='+Date.now();
	}
}

// Later, somewhere else, it's now much cleaner to do a cross-origin request
$.ajax({
	method: 'POST',
	url: 'http://example.com/some-api',
	data: {name: 'Alice', age: 17},
})

注意 当使用 cache:false 时,jQuery会在URL中添加一个 _ GET参数,带当前时间戳,以防止浏览器返回缓存的响应。这发生在 ajaxSend 事件之前,所以如果在上面的例子中您设置了 cache:false,那么那个 _ 参数就会被“移动”到 X-Proxy-URL 头部,并且不再有任何效果。相反,请将 cache 保持为其默认值 true,并手动将参数添加到代理URL中,就像上面的例子一样。

更多示例可以在 test/index.html 中找到。

安全性

尽管会检查引用者的主机名,但这很容易被伪造,所以在安全方面只能做这么多。但应该做的是定义白名单。用以下类型的标准填充它

  • 精确路径
    ['http://example.com/api/specific-method']
  • 具有单个正则表达式键的数组
    ['regex' => '%^http://example.com/api/%']
  • 具有任何 parse_url 组件以匹配的数组
    ['host' => 'example.com']
    ['host' => 'example.com', 'scheme' => 'https']

请求的URL必须至少匹配白名单中的一个标准才能被接受,否则将返回403。白名单也可以设置为空数组,以允许任何URL。

示例

<?php

require 'vendor/autoload.php';

Geekality\CrossOriginProxy::proxy([

	// URL component matching
	['host' => 'localhost'],
	['host' => 'example.com', 'scheme' => 'https'],

	// Exact matching
	['http://www.yr.no/place/Sweden/Stockholm/Stockholm/forecast.xml'],

	// Regex matching
	['regex' => '%^http://www.yr.no/place/Norway/%'],

]);

Cookie

发送到代理的Cookie将被忽略,因为浏览器将发送针对代理域的Cookie,而不是针对代理资源的Cookie。

如果请求需要设置cookie,例如会话ID,您可以设置X-Proxy-Cookie头,这样代理就会将其用作Cookie

同样,响应中的任何Set-Cookie头都会被浏览器消耗掉,无法访问,因此代理将任何Set-Cookie头重命名为X-Proxy-Set-Cookie

$.ajax({
	url: 'https://example.com',
	headers: {
		'X-Proxy-Cookie': 'jsessionid=AS348AF929FK219CKA9FK3B79870H;',
	},
	success: function(data, status, jqXHR) {
		var cookie = jqXHR.getResponseHeader('X-Proxy-Set-Cookie');
	}
})

cURL和zlib选项

您可以添加将在进行请求时附加到选项集的选项。您还可以关闭默认启用的zlib压缩。

<?php
	require 'vendor/autoload.php';

	$whitelist = [...];
	$opts = [CURLOPT_TIMEOUT => 5];
	$zlib = 'Off';

	Geekality\CrossOriginProxy::proxy($whitelist, $opts, $zlib);