调用 web api 时 $http 调用两次

Posted

技术标签:

【中文标题】调用 web api 时 $http 调用两次【英文标题】:$http call twice when calling web api 【发布时间】:2017-02-16 06:54:07 【问题描述】:

我使用ASP.NET MVC WEB API 2.0 创建了一个WEB API。 Web API 包含 loginregister 等方法。 我正在使用AngularJS 调用WEB API 方法,但它调用了两次。例如当我调用POST 方法时,它首先调用OPTION(我还没有创建任何OPTION 方法),然后它调用POST 方法。 我的代码:(用于登录) html

<div class="container" ng-controller="UserAccount">
    <form ng-submit="loginNow(user)">
        <input type="email" placeholder="Enter Email" required ng-model="user.email" id="txtEmail" class="form-control" />
        <br />
        <input type="password" placeholder="Enter Password" required ng-model="user.password" id="txtPwd" class="form-control" />
        <br />
        <button type="submit" class="btn btn-primary">Login</button>
    </form>
</div>

AngularJS 控制器:

$scope.loginNow = function (user) 
        $http.post(rootURL + "login",  email: user.email, password: user.password )
            .success(function (data) 
                if (data.id > 0) 
                    sessionStorage.setItem('userid', data.id);
                    window.location = '/';
                
            );

网页接口:

public class UsersController : ApiController
    
        private UserEntities db = new UserEntities();

        // GET: api/Users
        public IQueryable<Users_tbl> GetUsers_tbl()
        
            return db.Users_tbl;
        

        [ActionName("login")]
        public IHttpActionResult PostUser_Login(string email, string password)
        
            int id = db.Users_tbl.Where(a => a.email == email && a.password == password).Select(a => a.id).SingleOrDefault();
            if(id <= 0)
            
                return NotFound();
            
            return Ok(id);
        

        [ActionName("register")]
        public int PostUser_Register(string email, string password)
        
            int id = db.Users_tbl.Where(a => a.email == email).Select(a => a.id).SingleOrDefault();
            if(id > 0)
            
                return 1;
            
            Users_tbl user = new Users_tbl();
            user.email = email;
            user.password = password;
            try
            
                db.Users_tbl.Add(user);
                db.SaveChanges();
            
            catch
            
                return 2;
            
            return 0;
        


        // GET: api/Users/5
        [ResponseType(typeof(Users_tbl))]
        public IHttpActionResult GetUsers_tbl(int id)
        
            Users_tbl users_tbl = db.Users_tbl.Find(id);
            if (users_tbl == null)
            
                return NotFound();
            

            return Ok(users_tbl);
        


        // PUT: api/Users/5
        [ResponseType(typeof(void))]
        public IHttpActionResult PutUsers_tbl(int id, Users_tbl users_tbl)
        
            if (!ModelState.IsValid)
            
                return BadRequest(ModelState);
            

            if (id != users_tbl.id)
            
                return BadRequest();
            

            db.Entry(users_tbl).State = EntityState.Modified;

            try
            
                db.SaveChanges();
            
            catch (DbUpdateConcurrencyException)
            
                if (!Users_tblExists(id))
                
                    return NotFound();
                
                else
                
                    throw;
                
            

            return StatusCode(HttpStatusCode.NoContent);
        

        [ActionName("profile")]
        // POST: api/Users
        [ResponseType(typeof(Users_tbl))]
        public IHttpActionResult PostUsers_tbl(Users_tbl users_tbl)
        
            if (!ModelState.IsValid)
            
                return BadRequest(ModelState);
            

            db.Users_tbl.Add(users_tbl);
            db.SaveChanges();

            return CreatedAtRoute("DefaultApi", new  id = users_tbl.id , users_tbl);
        

        // DELETE: api/Users/5
        [ResponseType(typeof(Users_tbl))]
        public IHttpActionResult DeleteUsers_tbl(int id)
        
            Users_tbl users_tbl = db.Users_tbl.Find(id);
            if (users_tbl == null)
            
                return NotFound();
            

            db.Users_tbl.Remove(users_tbl);
            db.SaveChanges();

            return Ok(users_tbl);
        

        protected override void Dispose(bool disposing)
        
            if (disposing)
            
                db.Dispose();
            
            base.Dispose(disposing);
        

        private bool Users_tblExists(int id)
        
            return db.Users_tbl.Count(e => e.id == id) > 0;
        
    

【问题讨论】:

ActionName 特定于 MVC,而不是 Web API。您应该在您的 ApiController 路由上使用 Route。我不知道你在说什么,但当你说它应该调用Option 并且没有迹象表明它应该为一个调用调用两次登录方法。 您使用哪个服务器来托管/服务AngualrJS 代码? 【参考方案1】:

这是浏览器的默认行为。在发送跨域AJAX调用之前,浏览器发送pre-flight request(OPTION请求)Why?

查看here,了解如何最大限度地减少飞行前请求:

更新

如果您真的不想发送飞行前请求,您可以选择不违反同源政策 (SOP)。可能的解决方案是:

JSONP: 这是一种利用同源安全策略的 HTML 脚本元素异常的技术。脚本标签可以从不同的域加载 javascript,并且可以将查询参数添加到脚本 URI,以将有关您希望访问的资源的信息传递给托管脚本的服务器。 JSONP 服务器将返回在浏览器中评估的 JavaScript,该 JavaScript 调用页面上已经同意的 JavaScript 函数,以将服务器资源数据传递到您的页面。

服务器端代理:绕过同源策略执行跨域请求的另一种方法是根本不发出任何跨域请求!如果您使用驻留在您的域中的代理,您可以简单地使用它从您的后端代码访问外部服务并将结果转发到您的客户端代码。因为请求代码和代理在同一个域中,所以不违反SOP。

更新 您可以响应来自 Web API 2 的 OPTIONS 请求,这样就不会抛出 405 或 404。看看这里https://***.com/a/37425746/2509344

【讨论】:

【参考方案2】:

发生这种情况是因为,当页面加载时,在初始化期间它会发生一次,然后当你现在按下登录时它会再次调用。

【讨论】:

以上是关于调用 web api 时 $http 调用两次的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 redux-saga 调用我的 api 调用两次?

使用redux时,React主要组件被调用两次

onMessage:对传入消息调用两次回调 Flutter web

UITextField 清除按钮调用 didEndEditing 两次

端点在无限滚动中被调用两次

如何确保没有人可以两次调用api