首页 > 解决方案 > 从 PHP 控制器使用 request.post() 调用 python 脚本永远不会返回。为什么?

问题描述

我正在尝试从 Laravel 8 应用程序执行 python 脚本。python 脚本使用 Laravel 应用程序的 REST API,因此它必须进行身份验证。

如果 python 脚本在命令行上运行(开发平台是 Windows 10),则 python 脚本本身运行良好,但如果通过 shell_exec() 或 exec() 或 symfony/process() 运行,它会将 Laravel 应用程序关闭到我需要在不同的端口上重新启动应用程序或在控制台、laravel 日志中没有错误的情况下重新启动。

如果我从 python 脚本中取出 'requests.post()' 并用 print("Hello World") 替换它,它可以与 shell_exec()

问题:有人看到可能发生的事情吗?这似乎是一个权限问题,但我不确定。

脚注:我尝试了 Symfony,但收到了许多其他人报告的错误“无法获取随机数来初始化 Python 运行时”这似乎是 Windows 开发盒上的一个常见问题。解决了这个问题,但结果是一样的。对于将来看到此 python 初始化错误的任何人:在 Windows 构建环境中,您需要添加环境变量 SystemRoot,如下所示:$process = new Process([$python, $process_path, $argument1, $argument2], null, ['SystemRoot' => 'C:\WINDOWS']);

控制器

    public function startprocess(Request $request)
    {

        $python = "C:/Users/dev/AppData/Local/Programs/Python/Python38/python.exe";
        $process_path = "C:/Apache24/htdocs/project/resources/python/lambda/test.py";
        $complete_path = $python." ".$process_path;
        $output = [];
        $return_var = "";

//        exec($complete_path, $output, $return_var);
        $process = new Process([$python, $process_path], null, ['SystemRoot' => 'C:\WINDOWS']);
        $process->run();

        return view('admin.scheduledtasks_data', compact('output', 'return_var', 'complete_path'))->render();
    }

Python代码

import sys
import requests
from requests.exceptions import HTTPError
import re

url_login = 'http://127.0.0.1:8089/api/apilogin'

data = {
    'email': 'myemail@email.com',
    'password': 'password'}

returned_data = requests.post(url_login, data=data)  #<<THIS TAKES DOWN THE SERVER

这是 API 解析的内容

   public function APIlogin(Request $request)
    {

        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            return response([
                'message' => ['Please submit a valid email address and password combination.']
            ], 404);
        }

        $token = $user->createToken('user-token')->plainTextToken;

        $response = [
            'user' => $user,
            'token' => $token
        ];

        return response($response, 201);
    }

这是命令行中一个好的请求的样子

send: b'POST /api/apilogin HTTP/1.1 
Host: 127.0.0.1:8098 
User-Agent: python-requests/2.23.0 
Accept-Encoding: gzip, deflate 
Accept: */* 
Connection: keep-alive 
Content-Length: 48 
Content-Type: application/x-www-form-urlencoded'
send: b'email= (deleted) &password= (deleted)'
reply: 'HTTP/1.1 201 Created'
header: Host: 127.0.0.1:8098
header: Date: Fri, 13 Nov 2020 19:07:10 GMT
header: Connection: close
header: X-Powered-By: PHP/7.4.2
header: Cache-Control: no-cache, private
header: Date: Fri, 13 Nov 2020 19:07:10 GMT
header: Content-Type: application/json
header: X-RateLimit-Limit: 60
header: X-RateLimit-Remaining: 59

这是我使用 requests.post(url_login, data=data, timeout=3) 从 laravel 应用程序调用它并添加了“超时”但登录从未发生时的响应。没有超时,请求永远不会返回并且服务器会关闭

HTTP/1.1 200 OK
Host: 127.0.0.1:8102
Date: Fri, 13 Nov 2020 23:05:38 GMT
Connection: close
X-Powered-By: PHP/7.4.2
Content-Type: text/html; charset=UTF-8
Cache-Control: no-cache, private
Date: Fri, 13 Nov 2020 23:05:38 GMT
Set-Cookie: XSRF-TOKEN= (deleted); 
    expires=Sat, 14-Nov-2020 01:05:38 GMT; 
    Max-Age=7200; 
    path=/
Set-Cookie: icollect_session=(deleted); 
    expires=Sat, 14-Nov-2020 01:05:38 GMT; 
    Max-Age=7200; 
    path=/; 
    httponly
<td>
<textarea class="form-control" id="FormControlTextarea" rows="10" cols="300">
send: b&#039;POST /api/apilogin HTTP/1.1\r\n
Host: 127.0.0.1:8102\r\n
User-Agent: python-requests/2.23.0\r\n
Accept-Encoding: gzip, deflate\r\n
Accept: */*\r\n
Connection: keep-alive\r\n
Content-Length: 48\r\n
Content-Type: application/x-www-form-urlencoded\r\n\r\n&#039;
send: b&#039;email=(deleted)&amp;password=(deleted);
</textarea>
</td>

更新:帖子永远不会命中 api.php,所以问题一定是与 python 脚本无法回发到调用它的应用程序有关……但为什么呢?

更新:我正在使用 JS ajax 调用生成 python 脚本的 PHP 控制器。如果我在控制器中使用 PHP symfony process() 调用来调用包含 request.post() 的 python 脚本,则一旦 Symfony 抛出计时错误,ajax 最终会在 1 分钟后出错并出现 500 错误,然后 python 脚本继续和作品。现在只是为了了解为什么以及如何重新设计这个......

{message: "Maximum execution time of 60 seconds exceeded",…}
exception: "Symfony\Component\ErrorHandler\Error\FatalError"
file: "C:\Apache24\htdocs\laravel\vendor\symfony\process\Pipes\WindowsPipes.php"
line: 145
message: "Maximum execution time of 60 seconds exceeded"
trace: []

标签: pythonphpajaxsymfonypython-requests

解决方案


摆脱了 Symfony process() 并改为这个。发生的事情是 laravel 应用程序阻止 request.post 完成,因此服务器锁定......

在这里找到-谢谢@LucaM

function execInBackground($cmd) {
    if (substr(php_uname(), 0, 7) == "Windows"){
        pclose(popen("start /B ". $cmd, "r")); 
    }
    else {
        exec($cmd . " > /dev/null &");  
    }
} 

推荐阅读