代理访问平台资源解决unity-web的跨域问题

前言

针对网页资源跨域请求问题如果是自己服务器通常会在nginx添加header头

1
add_header Access-Control-Allow-Origin *;

来解决,如果不是自己的服务器对于动态数据交互请求我们通常的做法有jsonp或者请求先到自己服务器,然后自己服务器再和目标服务器交互获取响应返回给网页客户端,最近我们就遇到了这样的跨域问题,unity打包出来的web游戏内有访问平台用户头像的需求,而用户头像资源请求平台没有开放header的跨域设置,那只能使用后者通过自己的服务器代理访问资源。

设计规划

假设需要访问的ifeng的logo

经过我们自己的服务资源请求则变成(urlencode原始请求后追加到代理地址后面)

node实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var corss = require('cors');
var request = require('request');
var validUrl = require('valid-url');
var express = require('express');
var URL = require("url");

var app = express();

app.use(corss({
origin: '*'
}));

app.disable('x-powered-by');

app.get('/proxy/:url', function (req, res) {
if (req.params.url.length) {
var url = decodeURIComponent(req.params.url);
if (validUrl.isWebUri(url)) {
res.setHeader('State', 'YES');
request(url).pipe(res);
} else {
res.setHeader('State', 'NO');
res.statusCode = 404;
res.end()
}
} else {
res.setHeader('State', 'NO');
res.statusCode = 404;
res.end()
}
});

app.listen(3000);

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"name": "proxy",
"version": "1.0.0",
"description": "",
"main": "proxy.js",
"dependencies": {
"cors": "^2.8.4",
"corsproxy": "^1.5.0",
"express": "^4.16.3",
"request": "^2.87.0",
"valid-url": "^1.0.9"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "xingqiba",
"license": "MIT"
}

nginx代理到本地

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name -;
root /var/www/proxy;

location ~ /proxy {
proxy_pass http://127.0.0.1:3000;
}
}

supervisor管理代理服务

1
2
3
4
5
6
7
8
9
10
[program:proxy]
numprocs=1
command=/bin/bash /data/server/proxy/start.bash
user=root
autorestart=true
autostart=true
stdout_logfile=/var/log/supervisor/proxy_stdout.log
stderr_logfile=/var/log/supervisor/proxy_stderr.log
stdout_logfile_maxbytes=500MB
stdout_logfile_backups=2

php实现(以参数url传递)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php

$url = $_GET["url"];
if (!preg_match("~^https?://~i", $url)) {
$url = "http://" . $url;
}

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

$response_headers_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$response_headers = explode("\r\n", substr($response, 0, $response_headers_size));
$response_body = substr($response, $response_headers_size);
curl_close($ch);

$propagate_headers = array("content-type");
foreach ($response_headers as $header) {
if (in_array(strtolower(explode(": ", $header)[0]), $propagate_headers)) {
header($header);
}
}

header("Access-Control-Allow-Origin: *");

echo $response_body;

结论

  • 功能已经实现,但适用吗?显然浪费了带宽,可以优化为先保存到本地服务器,然后作为本地服务器资源的一部分返回给客户端

支持

  • QQ群 233415606