Seem to Have the Wrong Content Type When POSTing w

2019-07-30 11:09发布

问题:

I am looking to make use of Chai-HTTP for some testing. Naturally I want to test more than my GETs however I seem to be hitting a major roadblock when attempting to make POSTs.

In an attempt to figure out why my POSTs weren't working I began hitting them against a POST test server.

Here is a POST attempt formatted using an entirely different toolchain (Jasmine-Node and Frisby) for testing (that works just fine):

frisby.create('LOGIN')
  .post('http://posttestserver.com/post.php', {
    grant_type:'password',
    username:'helllo@world.com',
    password:'password'
  })
  .addHeader("Token", "text/plain")
  .expectStatus(200)
  })
.toss();

Which results in:

Time: Mon, 27 Jun 16 13:40:54 -0700
Source ip: 204.191.154.66

Headers (Some may be inserted by server)
REQUEST_URI = /post.php
QUERY_STRING = 
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 19216
REMOTE_ADDR = 204.191.154.66
HTTP_CONNECTION = close
CONTENT_LENGTH = 64
HTTP_HOST = posttestserver.com
HTTP_TOKEN = text/plain
CONTENT_TYPE = application/x-www-form-urlencoded
UNIQUE_ID = V3GPVkBaMGUAAB1Uf04AAAAc
REQUEST_TIME_FLOAT = 1467060054.9575
REQUEST_TIME = 1467060054

Post Params:
key: 'grant_type' value: 'password'
key: 'username' value: 'hello@world.com'
key: 'password' value: 'password'
Empty post body.

Upload contains PUT data:
grant_type=password&username=hello%40world.com&password=password

And here is a POST attempt using Chai and Chai-HTTP. I would expect this to work the same as the above example using Jasmine and Frisby, however, you'll see the actual request differs in several ways.

describe('/post.php', function() {

  var endPointUnderTest = '/post.php';

  it('should return an auth token', function(done) {
    chai.request('http://posttestserver.com')
      .post(endPointUnderTest)
      .set('Token', 'text/plain')
      .send({
        grant_type: 'password',
        username: 'hello@world.com',
        password: 'password'
      })
      .end(function(err, res) {
        console.log(res);
        res.should.have.status(200);
        done();
      });
  });
});

Which results in:

Time: Tue, 28 Jun 16 06:55:50 -0700
Source ip: 204.191.154.66

Headers (Some may be inserted by server)
REQUEST_URI = /post.php
QUERY_STRING = 
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 1409
REMOTE_ADDR = 204.191.154.66
HTTP_CONNECTION = close
CONTENT_LENGTH = 76
CONTENT_TYPE = application/json
HTTP_TOKEN = text/plain
HTTP_USER_AGENT = node-superagent/2.0.0
HTTP_ACCEPT_ENCODING = gzip, deflate
HTTP_HOST = posttestserver.com
UNIQUE_ID = V3KB5kBaMGUAAErPF6IAAAAF
REQUEST_TIME_FLOAT = 1467122150.9125
REQUEST_TIME = 1467122150

No Post Params.

== Begin post body ==
{"grant_type":"password","username":"hello@world.com","password":"password"}
== End post body ==

Upload contains PUT data:
{"grant_type":"password","username":"hello@world.com","password":"password"}

Notice the difference in CONTENT_TYPE, Post Params and PUT data in particular (I think this is the source of my problem).

Where Jasmine/Frisby would submit the POST using the 'application/x-www-form-urlencoded' format, Chai-HTTP seems to be using the 'application/json' format.

Am I somehow misusing Chai-HTTP's POST capabilities? Or does Chai-HTTP not allow for 'application/x-www-form-urlencoded' POST requests? I do not seem to be able to resolve this and it is the final hurdle for me to jump to make the transition to using a Mocha/Chai toolchain for my testing (which is the goal, I would prefer to not use a different library unless it's absolutely necessary).

回答1:

Having discussed this further on Chai-HTTP's Git-Hub page, I was able to find out that this is expected behaviour of SuperAgent, the HTTP request library under the hood of Chai-HTTP, which auto-detects the content-type based on what kind of data is contained in the .send() call.

I stumbled across this particular question as well which helped clarify what the difference between content-types actually was.

If anyone else runs into this problem, I've learned that Chai-HTTP's POST requests can be altered quite easily (kudos to meeber's help here) using calls like this:

//Override auto-detection by specifying the header explicitly
.set('content-type', 'application/x-www-form-urlencoded')

//Select the type 'form'
.type('form')

//Pass multiple strings in send instead of using an object
.send('grant_type=password')
.send('username=hello@world.com')
.send('password=password')

Creating a request that looks like this:

describe('/post.php', function() {

  var endPointUnderTest = '/post.php';

  it('should return an auth token', function(done) {
    chai.request('http://posttestserver.com')
      .post(endPointUnderTest)
      .set('Token', 'text/plain')
      .set('content-type', 'application/x-www-form-urlencoded')
      .type('form')
      .send('grant_type=password')
      .send('username=hello@world.com')
      .send('password=password')
      .end(function(err, res) {
        console.log(res);
        res.should.have.status(200);
        done();
      });
  });
});