0

在 V8Js 中运行 Axios 时,所有请求都失败,因为XMLHttpRequest不可用。

我们如何使 axios 请求在服务器端工作?

4

1 回答 1

1

可以使用 V8J 将 PHP 函数或类绑定到 JavaScript。

例如,在 PHP 中,您可以:

$v8 = new \V8Js();

$v8->sayHello = function($name) {
    print('Hello ' . $name);
};

$js = 'PHP.sayHello('Bob')';

$v8->executeString($js);

执行时,这将产生字符串“Hello Bob”。

因此,知道了这一点,我们可以在 PHP 中创建 XMLHttpRequest,然后以相同的方式将其绑定到 JS。

首先,我们需要创建 XMLHttpRequest 类来实际发出请求。为此,我使用 Guzzle。

<?php

namespace App\Http\Helpers;

use GuzzleHttp\Client;

class XMLHttpRequest
{
    protected $url;

    protected $method;

    public $status;

    public $statusText;

    public $readyState;

    public $responseData;

    public $responseHeaders;

    public $onreadystatechange;

    public function open($method, $url)
    {
        $this->method   = $method;
        $this->url      = $url;
    }

    public function send($data = '')
    {
        $headers = [];
        // Here I am using a Laravel function to fetch the session id but this could be replaced
        if($sessionId = request()->session()->getId()) {
            // Set whatever auth values are needed for your application
            $headers['Cookie'] = 'session=' . $sessionId;
        }

        $options = [
            'http_errors' => false,
            'headers'     => $headers,
            'body'        => $data
        ];

        $client = new Client();

        $response = $client->request($this->method, $this->url, $options);

        $this->responseHeaders = $response->getHeaders();
        $this->responseData    = (string) $response->getBody();
        $this->status          = $response->getStatusCode();
        $this->readyState      = 4;
        $this->statusText      = $response->getReasonPhrase();

        if (is_callable($this->onreadystatechange)) {
            call_user_func($this->onreadystatechange);
        }

    }

}

然后在创建 V8Js 实例后,我们可以附加新库:

$v8 = new \V8Js();

$v8->XMLHttpRequest = function () {
    return new XMLHttpRequest;
};

现在我们需要告诉 Axios 使用我们的库。我们可以通过首先创建一个适配器来做到这一点:

const XMLHttpRequest = PHP.XMLHttpRequest;
const adapter = (config) => {
    return new Promise(function(resolve, reject) {
        const xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = () => {
            const response = {
                data: xhttp.responseData,
                status: xhttp.status,
                statusText: xhttp.statusText,
                headers: xhttp.responseHeaders,
                config: config,
                request: {}
            };
            settle(resolve, reject, response);
        };

        xhttp.open(config.method, config.baseURL + config.url);
        xhttp.send();
    })
}

然后添加一个拦截器来设置适配器和baseURL:

axios.interceptors.request.use(config => {
    config.baseURL = 'https://YOUR-URL.com'
    config.adapter = adapter
    return config
})

在此之后使用正常axios.post将工作服务器端。

于 2020-06-04T12:25:31.890 回答