网页设计学习笔记

HTML,CSS,JavaScript

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

由于安全上的限制,在浏览器中使用 JavaScript 不能直接访问跨域的资源。我们可以通过服务器来中转:用 PHP 编写一个简单地跨域访问代理。

一般需要支持 GET 和 POST 这两种 HTTP 请求。对于 GET 方式,我们可以用 fopen,file_get_contents 和 curl 来抓取资源。在网上查询得知 curl 速度会快一些,而且会缓存 DNS 信息,所以就使用 curl 来处理。例子如下:

function curlget($url) {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HEADER, false);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $data = curl_exec($ch);
  if ($data === false) {
    header('HTTP/1.1 400 Bad Request');
    exit;
  } else {
  echo $data;
}

我们也可以用 curl 来处理 POST 请求。我们至少需要区分两种 POST 请求:第一种的 Content-Type 为 application/x-www-form-urlencoded,仅仅用于提交参数;而第二种的 Content-Type 为 multipart/form-data,用于上传文件。POST 请求的例子如下:

function curlpost($url, $data) {
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HEADER, false);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
  $data = curl_exec($ch);
  if ($data === false) {
    header('HTTP/1.1 400 Bad Request');
    exit;
  } else {
  echo $data;
}

其中 curl_setopt 的 CURLOPT_POSTFIELDS 选项中,如果 $data 是字符串,curl 提交时将设置 Content-Type 为 application/x-www-form-urlencoded;如果 $data 是包含 'file' 项的数组,curl 提交时将设置 Content-Type 为 multipart/form-data。

现在我们假定:客服端将要访问的地址作为 URL 的 path 参数发送过来,即 JavaScript 代码类似于下面:

var path = 'http://some.domain.com/some/page/';
var url = 'http://example.com/?path=' + encodeURIComponent(url);

在 PHP 中,不管是 GET 方式还是 POST 方式的请求,URL 中的参数(即上面的 path 值)都放在 $_GET 数组中。而 POST 方式提交的数据,如果是 application/x-www-form-urlencoded 的请求,放在 $_POST 数组中;如果是 multipart/form-data 的请求,所上传的文件存放在临时目录中,文件的基本信息放在 $_FILES 数组中。理解了这些知识后,我们可以用下面的代码来处理请求:

var $url = $_GET['path'];

switch ($_SERVER['REQUEST_METHOD']) {
    case "GET":
        curlget($url);
        break;
    case "POST":
        switch($_SERVER['CONTENT_TYPE']) {
            case 'application/x-www-form-urlencoded':
                $data = http_build_request($_POST);
                break;
            case 'multipart/form-data':
                $tempname = $_FILES['file']['tmp_name'];
                $basename = basename($_FILES['file']['name']);
                $origname = sys_get_temp_dir() . '/' . $basename;
                move_uploaded_file($tempname, $origname);
                chdir(sys_get_temp_dir());
                $data = array('name' => 'file', 'filename' => '@' . $basename);
                break;
            default:
                exit;
        }
        curlpost($url, $data);
        break;
    default:
        exit;
}

其中使用 chdir 函数是为了保证 curl 提交文件时不包含路径。

参考资料:
[1] JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls
[2] PHP 手册:file_get_contents
[3] PHP 手册:cURL 函数
[4] file_get_contents VS CURL, what has better performance?
[5] 简评file_get_contents与curl 效率及稳定性
[6] PHP 手册:$_GET
[7] PHP 手册:$_POST
[8] PHP 手册:$_FILES
[9] PHP 手册:$_SERVER
[A] PHP 手册:http_build_query
[B] PHP 手册:move_uploaded_file
[C] HTML 4.01 Specification - Forms
[D] Get “Content-Type” header of request in PHP
[E] Form Data Processing
[F] PHP 文件上传
[G] arkadi / phpproxy / source - Bitbucket
[H] CORS Proxy
[I] node.js based CORS proxy

posted on 2012-07-03 21:49  zoho  阅读(2934)  评论(0编辑  收藏  举报