In Laravel default timeout for Http Client requests is 30 seconds. But I want to change it to 5 seconds. I already know that it is possible by calling timeout(5)
function on Http (PendingRequest) instance:
Http::timeout(5)->get('www.example.com');
But I don't want to call it each time I access Http facade. I want it to be its default behaviour. What I tried so far:
use Illuminate\Http\Client\Factory;
class AppServiceProvider extends ServiceProvider
public function register()
$this->app->bind(Factory::class, static fn () => (new Factory)->withOptions(['timeout' => 5]));
}
It was doing what I need but I got faced a problem when I call Http client more than one time in one API request.
For example I have an API to upload document and then generate contract number for that to store in database:
$response1 = Http::baseUrl('www.storageservice.com')->attach('document', 'file_contents', 'document.pdf')->post('/upload');
$response2 = Http::baseUrl('www.numbergenerator.com')
// ->post('/generate/number');
If I debug $response2
I can see the document
file attached to its body. Which means I am using exact same Http instance with first API call for second one.
That happens just because the code I have written in AppServiceProvider
.
When I delete the line in AppServiceProvider
everything works well again but default timeout is still 30 seconds.
I know that for each Http
call I can call new()
method to create new instance of it like:
$response1 = Http::new()->baseUrl('www.storageservice.com')->attach('document', 'file_contents', 'document.pdf')->post('/upload');
$response2 = Http::new()->baseUrl('www.numbergenerator.com')
// ->post('/generate/number');
but it seems reverse engineering a bit. If I need to call a function each time so it would be timeout
surely.
Any thought?
I solved my problem creating new Class that extends Factory
class and binding them.
use Illuminate\Http\Client\Factory;
use Illuminate\Contracts\Events\Dispatcher;
class AppServiceProvider extends ServiceProvider
public function boot(): void
{
$this->app->bind(Factory::class, function ($app) {
return new MyCustomHttpClientFactory($app->make(Dispatcher::class));
});
}
MyCustomHttpClientFactory
:
use Illuminate\Http\Client\Factory;
class MyCustomHttpClientFactory extends Factory
{
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
return tap($this->newPendingRequest(), function ($request) {
$request
//This line has changed from the base factory class
->withOptions(['timeout' => 5]);
})->{$method}(...$parameters);
}
}
Whenever Factory
class get needed by app new instance of MyCustomHttpClientFactory
will be used. And in MyCustomHttpClientFactory
I am looking for any method call then catch $this->newPendingRequest()
by tap
function then attach withOptions
method to it.
Btw timeout set in __constructor
of PendingRequest
class:
public function __construct(Factory $factory = null)
{
$this->factory = $factory;
$this->middleware = new Collection;
$this->asJson();
$this->options = [
'connect_timeout' => 10,
'http_errors' => false,
'timeout' => 30,
];
$this->beforeSendingCallbacks = collect([function (Request $request, array $options, PendingRequest $pendingRequest) {
$pendingRequest->request = $request;
$pendingRequest->cookies = $options['cookies'];
$pendingRequest->dispatchRequestSendingEvent();
}]);
}