Http请求多浏览器的烦恼

Posted

技术标签:

【中文标题】Http请求多浏览器的烦恼【英文标题】:Http requests multi browser troubles 【发布时间】:2016-06-15 09:42:12 【问题描述】:

我正在使用angularJs 构建laravel 5.1

当用户单击一个按钮时,我想发送一个destroy request 以将其从数据库中删除,然后在完成后发送一个get request 以获取新数据,因为新数据已被删除。

所以我将我的方法附加到按钮上的 ng-click 事件上,这很有效,它会命中方法。

然后我运行.destroy request。在.destroy.then() 方法中,我想调用另一个具有.get request 的方法。

这在 Safari 中完美运行,但在 Chrome 或 Firefox 中不起作用。

Here is my code for the controller,点击删除按钮时调用的方法是deleteOpportunity()

$scope.getOpportunities = function()
    
        UBOService.get()
            .then(function successCallback(responsed) 
                $scope.opportunities = responsed.data;
            , function errorCallback(response) 
                $scope.error = response;
            );
    
$scope.deleteOpportunity = function()
    

                UBOService.destroy($scope.activeItem.id)
                    .then(function successCallback(response) 
                        $scope.getOpportunities();

                        return false;
                    , function errorCallback(response) 
                        $scope.error = response;
                    );

    

我的服务代码:

app.service('UBOService', function($http) 

    return 
        get : function() 
            return $http.get('/api/user-booked-opportunities');
        ,

        destroy : function(id) 

            return $http.delete('/api/user-booked-opportunities/' +  id);
        
    
)

我做错了吗?有什么我想念的吗? Safari 与此代码的交互方式有何不同?

【问题讨论】:

是否有异常写入控制台?如果没有,它甚至可以调用 $http.get 吗? 嗨!我刚刚用 L5.1 和 AngularJS 1.47 完成了一个项目。我可以建议您在“then”块之后使用 .finally() 而不是“,function()”。此外,我建议您在删除某些内容后不要进行任何 http 调用,而是从您存储数据的变量中删除这些对象。如果您需要进一步说明,我可以在单独的评论中为您提供更多信息和代码示例。 :) 什么在 Safari 中不起作用?删除请求?或获取请求?或按钮单击本身?另外,您在 laravel 部分中使用的是什么类型的控制器?控制台有错误吗? 您可能还有其他问题,但为了节省一些电话,您可以在销毁一个机会时返回新的机会列表,这样您就不必单独拨打电话。 Orrrr 我刚看了@Cowwando 的评论,按他说的做,我平时就是这样做的。 将分号放在 $scope.deleteOpportunity = function() 中是否有帮助:; $scope.deleteOpportunity = function() 【参考方案1】:

如果您返回successCallbackerrorCallback 中的值,则返回的值将用于解析promise。 尝试定义一个 $q.deferred ,它将在获取 $http 成功时与数据一起解决。

$scope.deleteOpportunity = function() 
            var deferred = $q.defer();

            UBOService.destroy($scope.activeItem.id)
                .then(function successCallback(response) 
                    UBOService.get().then(function(response)
                        $scope.opportunities = response.data;
                        deferred.resolve(response.data);
                    ;
                , function errorCallback(response) 
                    $scope.error = response;
                );
        return deferred.promise;

【讨论】:

【参考方案2】:

我猜这是一个 CORS 问题。此外,如果您将客户端与服务器端分离,通常会发生此问题。您需要创建一个 before 中间件来处理此类问题。

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware

  /**
  * Handle an incoming request.
  *
  * @param  \Illuminate\Http\Request  $request
  * @param  \Closure  $next
  * @return mixed
  */
 public function handle($request, Closure $next)
 
    /** 
    * The access control allow origin and 
    * allow credential is set to * and true 
    * because i allow request from different domains
    * to hit the server
    */
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Credentials: false');
    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization');

    if ($request->getMethod() == "OPTIONS") 
        $headers = array(
            'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers'=> 'X-Requested-With, content-type',);
        return Response::make('', 200, $headers);
    

    return $next($request);
 

并在事物的角度添加此配置块

app.config(['$httpProvider', function ($httpProvider) 

  $httpProvider.defaults.useXDomain = false;
  $httpProvider.defaults.withCredentials = false;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];

]);

【讨论】:

【参考方案3】:

很难根据您发布的参数来衡量,但仅基于您说这在 Safari 中完美运行,但在 Chrome 或 Firefox 中无法运行,听起来这可能是 CORS 问题。

Firefox 和 Chrome 对跨域请求的要求与 Safari 不同。这个destroy 操作的 Laravel api 端点是否与 Angular 应用程序位于同一位置? API 返回的 Access-Control-Allow-Origin 标头是什么?

尝试在 Laravel 中添加类似以下的内容,看看它是否使这个块在这些浏览器中保持一致:

App::before(function($request) 
  // Enable CORS 
  // In production, replace * with http://yourdomain.com 
  header("Access-Control-Allow-Origin: *");
  header('Access-Control-Allow-Credentials: true');

  if (Request::getMethod() == "OPTIONS") 
    // The client-side application can set only headers allowed in Access-Control-Allow-Headers
    $headers = [
      'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
      'Access-Control-Allow-Headers' => 'X-Requested-With, Content-Type, X-Auth-Token, Origin, Authorization'
    ];
    return Response::make('You are connected to the API', 200, $headers);
  
);

(^ source)

【讨论】:

以上是关于Http请求多浏览器的烦恼的主要内容,如果未能解决你的问题,请参考以下文章

HTTP请求报文和响应报文

http与ajax的区别

http报文详解

HTTP中的请求与响应

单点登入到多系统登入分析设计

axios 是如何封装 HTTP 请求的