问题
Does anyone have any suggestions (or a regular expression) for parsing the HTTP Accept header?
I am trying to do some content-type negotiation in ASP.NET MVC. There doesn't seem to be a built in way (which is fine, because there are a lot of schools of thought here), but the parsing is not entirely trivial and I would rather not re-invent the wheel if someone has already done it well and is willing to share.
回答1:
Have you seen this article? It gives a pretty comprehensive implementation for parsing the Accept header and subsequently doing something useful with it.
回答2:
As of .NET 4.5 (I think—Microsoft have made info on framework versions < 4.5 rather obscure these days), you can use one of the the built in parsers from System.Net.Http.Headers:
public IOrderedEnumerable<MediaTypeWithQualityHeaderValue> GetMediaTypes(string headerValue) =>
headerValue?.Split(',')
.Select(MediaTypeWithQualityHeaderValue.Parse)
.OrderByDescending(mt => mt.Quality.GetValueOrDefault(1));
Then you can do something like this:
var headerValue = "application/json, text/javascript, */*; q=0.01";
var mediaTypes = GetMediaTypes(headerValue);
Giving you a nice list of all the media types, where the preferred option is the first item. Here's a LINQPad Dump of the mediaTypes result from the example:
Hat tip to this answer, for getting me on the right track.
回答3:
I've written a parser in PHP. It's not complex, but it will give you an array of mime types in order of preference.
回答4:
Found another implementation in php here
回答5:
After reading the xml.com article I decided to not write a function for the Accept header myself ;)
Fortunately the article points to a good library: https://code.google.com/p/mimeparse/ - in my case I need it as a Node.js module: https://github.com/kriskowal/mimeparse
回答6:
Building on https://stackoverflow.com/a/49011308/275501 from https://stackoverflow.com/users/43140/mark-bell above:
public class MyController : Controller
{
[HttpGet]
[Route("/test")]
public ActionResult Index() {
// does this request accept HTML?
var acceptsHTML = IsAcceptable("text/html");
var model = FetchViewModel();
return acceptsHTML ? (ActionResult) View(model) : Ok(model);
}
private bool IsAcceptable(string mediaType) =>
Request.Headers["Accept"].Any(headerValue =>
!string.IsNullOrWhiteSpace(headerValue) &&
headerValue.Split(",").Any(segment => MediaTypeHeaderValue.Parse(segment).MediaType == mediaType));
private object FetchViewModel() {
return new { Description = "To be completed" };
}
}
回答7:
The RFC is quite complex. If the regex where to follow these rules to the letter, it would become several lines long.
If you already have the Accept-header, and ignore the quotes and the parameters, you could do something like this to match each pair:
/([^()<>@,;:\\"\/[\]?={} \t]+)\/([^()<>@,;:\\"\/[\]?={} \t]+)/
* is included in the character class, so it does not need any special case in the regex.
来源:https://stackoverflow.com/questions/255436/parse-accept-header